mirror of
https://github.com/knex/knex.git
synced 2025-11-10 06:44:11 +00:00
whatwg url connection string parsing (#3702)
This commit is contained in:
parent
5d3801cf51
commit
4da221ba4f
@ -1,13 +1,23 @@
|
|||||||
const url = require('url');
|
|
||||||
const { parse } = require('pg-connection-string');
|
const { parse } = require('pg-connection-string');
|
||||||
const parsePG = parse;
|
const parsePG = parse;
|
||||||
const isWindows = process && process.platform && process.platform === 'win32';
|
const isWindows = process && process.platform && process.platform === 'win32';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param str
|
||||||
|
* @returns {URL}
|
||||||
|
*/
|
||||||
|
function tryParse(str) {
|
||||||
|
try {
|
||||||
|
return new URL(str);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = function parseConnectionString(str) {
|
module.exports = function parseConnectionString(str) {
|
||||||
const parsed = url.parse(str, true);
|
const parsed = tryParse(str);
|
||||||
let { protocol } = parsed;
|
const isDriveLetter = isWindows && parsed && parsed.protocol.length === 2;
|
||||||
const isDriveLetter = isWindows && protocol && protocol.length === 2;
|
if (!parsed || isDriveLetter) {
|
||||||
if (protocol === null || isDriveLetter) {
|
|
||||||
return {
|
return {
|
||||||
client: 'sqlite3',
|
client: 'sqlite3',
|
||||||
connection: {
|
connection: {
|
||||||
@ -15,6 +25,7 @@ module.exports = function parseConnectionString(str) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
let { protocol } = parsed;
|
||||||
if (protocol.slice(-1) === ':') {
|
if (protocol.slice(-1) === ':') {
|
||||||
protocol = protocol.slice(0, -1);
|
protocol = protocol.slice(0, -1);
|
||||||
}
|
}
|
||||||
@ -27,6 +38,10 @@ module.exports = function parseConnectionString(str) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {URL} parsed
|
||||||
|
* @returns {{}}
|
||||||
|
*/
|
||||||
function connectionObject(parsed) {
|
function connectionObject(parsed) {
|
||||||
const connection = {};
|
const connection = {};
|
||||||
let db = parsed.pathname;
|
let db = parsed.pathname;
|
||||||
@ -46,20 +61,15 @@ function connectionObject(parsed) {
|
|||||||
if (parsed.port) {
|
if (parsed.port) {
|
||||||
connection.port = parsed.port;
|
connection.port = parsed.port;
|
||||||
}
|
}
|
||||||
if (parsed.auth) {
|
if (parsed.username || parsed.password) {
|
||||||
const idx = parsed.auth.indexOf(':');
|
connection.user = decodeURIComponent(parsed.username);
|
||||||
if (idx !== -1) {
|
|
||||||
connection.user = parsed.auth.slice(0, idx);
|
|
||||||
if (idx < parsed.auth.length - 1) {
|
|
||||||
connection.password = parsed.auth.slice(idx + 1);
|
|
||||||
}
|
}
|
||||||
} else {
|
if (parsed.password) {
|
||||||
connection.user = parsed.auth;
|
connection.password = decodeURIComponent(parsed.password);
|
||||||
}
|
}
|
||||||
}
|
if (parsed.searchParams) {
|
||||||
if (parsed.query) {
|
for (const [key, value] of parsed.searchParams.entries()) {
|
||||||
for (const key in parsed.query) {
|
connection[key] = value;
|
||||||
connection[key] = parsed.query[key];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return connection;
|
return connection;
|
||||||
|
|||||||
@ -39,7 +39,9 @@ test('parses standard connections without password', function (t) {
|
|||||||
test('mysql connection protocol with query string params', function (t) {
|
test('mysql connection protocol with query string params', function (t) {
|
||||||
t.plan(1);
|
t.plan(1);
|
||||||
t.deepEqual(
|
t.deepEqual(
|
||||||
parseConnection('mysql://user:pass@path.to.some-url:3306/testdb?foo=bar'),
|
parseConnection(
|
||||||
|
'mysql://user:pass@path.to.some-url:3306/testdb?foo=bar&anotherParam=%2Fa%2Fb%2Fc'
|
||||||
|
),
|
||||||
{
|
{
|
||||||
client: 'mysql',
|
client: 'mysql',
|
||||||
connection: {
|
connection: {
|
||||||
@ -49,6 +51,92 @@ test('mysql connection protocol with query string params', function (t) {
|
|||||||
port: '3306',
|
port: '3306',
|
||||||
database: 'testdb',
|
database: 'testdb',
|
||||||
foo: 'bar',
|
foo: 'bar',
|
||||||
|
anotherParam: '/a/b/c',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('mysql connection protocol allows skip username', function (t) {
|
||||||
|
t.plan(1);
|
||||||
|
t.deepEqual(
|
||||||
|
parseConnection(
|
||||||
|
'mysql://:pass@path.to.some-url:3306/testdb?foo=bar&anotherParam=%2Fa%2Fb%2Fc'
|
||||||
|
),
|
||||||
|
{
|
||||||
|
client: 'mysql',
|
||||||
|
connection: {
|
||||||
|
user: '',
|
||||||
|
password: 'pass',
|
||||||
|
host: 'path.to.some-url',
|
||||||
|
port: '3306',
|
||||||
|
database: 'testdb',
|
||||||
|
foo: 'bar',
|
||||||
|
anotherParam: '/a/b/c',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('mysql connection protocol allows skip password', function (t) {
|
||||||
|
t.plan(1);
|
||||||
|
t.deepEqual(
|
||||||
|
parseConnection('mysql://username@path.to.some-url:3306/testdb'),
|
||||||
|
{
|
||||||
|
client: 'mysql',
|
||||||
|
connection: {
|
||||||
|
user: 'username',
|
||||||
|
host: 'path.to.some-url',
|
||||||
|
port: '3306',
|
||||||
|
database: 'testdb',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('mysql connection protocol allows empty password', function (t) {
|
||||||
|
t.plan(1);
|
||||||
|
t.deepEqual(
|
||||||
|
parseConnection('mysql://username:@path.to.some-url:3306/testdb'),
|
||||||
|
{
|
||||||
|
client: 'mysql',
|
||||||
|
connection: {
|
||||||
|
user: 'username',
|
||||||
|
host: 'path.to.some-url',
|
||||||
|
port: '3306',
|
||||||
|
database: 'testdb',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('decodes username and password', function (t) {
|
||||||
|
t.plan(1);
|
||||||
|
t.deepEqual(parseConnection('mysql://user%3A@path.to.some-url:3306/testdb'), {
|
||||||
|
client: 'mysql',
|
||||||
|
connection: {
|
||||||
|
user: 'user:',
|
||||||
|
host: 'path.to.some-url',
|
||||||
|
port: '3306',
|
||||||
|
database: 'testdb',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('do not encode password', function (t) {
|
||||||
|
t.plan(1);
|
||||||
|
t.deepEqual(
|
||||||
|
parseConnection(
|
||||||
|
'mysql://user:password-start:rest@path.to.some-url:3306/testdb?'
|
||||||
|
),
|
||||||
|
{
|
||||||
|
client: 'mysql',
|
||||||
|
connection: {
|
||||||
|
user: 'user',
|
||||||
|
password: 'password-start:rest',
|
||||||
|
host: 'path.to.some-url',
|
||||||
|
port: '3306',
|
||||||
|
database: 'testdb',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -93,7 +181,7 @@ test('parses mssql connections, aliasing host to server and adding extra params'
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('assume a path is mysql', function (t) {
|
test('assume a path is sqlite', function (t) {
|
||||||
t.plan(1);
|
t.plan(1);
|
||||||
t.deepEqual(parseConnection('/path/to/file.db'), {
|
t.deepEqual(parseConnection('/path/to/file.db'), {
|
||||||
client: 'sqlite3',
|
client: 'sqlite3',
|
||||||
@ -103,18 +191,61 @@ test('assume a path is mysql', function (t) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('assume a relative path is sqlite', function (t) {
|
||||||
|
t.plan(1);
|
||||||
|
t.deepEqual(parseConnection('./path/to/file.db'), {
|
||||||
|
client: 'sqlite3',
|
||||||
|
connection: {
|
||||||
|
filename: './path/to/file.db',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('parse windows path as sqlite config', function (t) {
|
||||||
|
t.plan(1);
|
||||||
|
// reset process.platform to windows, reset require cache, require fresh
|
||||||
|
// after test restore back
|
||||||
|
const originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
|
||||||
|
|
||||||
|
Object.defineProperty(process, 'platform', {
|
||||||
|
value: 'win32',
|
||||||
|
});
|
||||||
|
|
||||||
|
const modulePath = require.resolve('../../lib/util/parse-connection');
|
||||||
|
const oldCache = require.cache[modulePath];
|
||||||
|
delete require.cache[modulePath];
|
||||||
|
|
||||||
|
const parseConnection = require('../../lib/util/parse-connection');
|
||||||
|
try {
|
||||||
|
t.deepLooseEqual(
|
||||||
|
parseConnection('C:\\Documents\\Newsletters\\Summer2018.pdf'),
|
||||||
|
{
|
||||||
|
client: 'sqlite3',
|
||||||
|
connection: {
|
||||||
|
filename: 'C:\\Documents\\Newsletters\\Summer2018.pdf',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
Object.defineProperty(process, 'platform', originalPlatform);
|
||||||
|
require.cache[modulePath] = oldCache;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('#852, ssl param with PG query string', function (t) {
|
test('#852, ssl param with PG query string', function (t) {
|
||||||
t.plan(1);
|
t.plan(1);
|
||||||
t.deepLooseEqual(
|
t.deepLooseEqual(
|
||||||
parseConnection('postgres://user:password@host:0000/database?ssl=true')
|
parseConnection('postgres://user:password@host:0000/database?ssl=true'),
|
||||||
.connection,
|
|
||||||
{
|
{
|
||||||
|
client: 'postgres',
|
||||||
|
connection: {
|
||||||
host: 'host',
|
host: 'host',
|
||||||
port: '0000',
|
port: '0000',
|
||||||
user: 'user',
|
user: 'user',
|
||||||
password: 'password',
|
password: 'password',
|
||||||
database: 'database',
|
database: 'database',
|
||||||
ssl: true,
|
ssl: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -122,15 +253,17 @@ test('#852, ssl param with PG query string', function (t) {
|
|||||||
test('support postgresql connection protocol', function (t) {
|
test('support postgresql connection protocol', function (t) {
|
||||||
t.plan(1);
|
t.plan(1);
|
||||||
t.deepLooseEqual(
|
t.deepLooseEqual(
|
||||||
parseConnection('postgresql://user:password@host:0000/database?ssl=true')
|
parseConnection('postgresql://user:password@host:0000/database?ssl=true'),
|
||||||
.connection,
|
|
||||||
{
|
{
|
||||||
|
client: 'postgresql',
|
||||||
|
connection: {
|
||||||
host: 'host',
|
host: 'host',
|
||||||
port: '0000',
|
port: '0000',
|
||||||
user: 'user',
|
user: 'user',
|
||||||
password: 'password',
|
password: 'password',
|
||||||
database: 'database',
|
database: 'database',
|
||||||
ssl: true,
|
ssl: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user