diff --git a/CHANGELOG.md b/CHANGELOG.md index 68a94269..c1e5d63f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Change log for amqplib +## Unreleased + * Replace url-parse lib with native URL interface + ## Chagnes in v0.10.0 * Use Native promises ([PR 689](https://github.com/amqp-node/amqplib/pull/689), thank you diff --git a/lib/connect.js b/lib/connect.js index 478dd76c..57d034f0 100644 --- a/lib/connect.js +++ b/lib/connect.js @@ -6,7 +6,6 @@ 'use strict'; -var URL = require('url-parse'); var QS = require('querystring'); var Connection = require('./connection').Connection; var fmt = require('util').format; @@ -43,16 +42,16 @@ var CLIENT_PROPERTIES = { }; // Construct the main frames used in the opening handshake -function openFrames(vhost, query, credentials, extraClientProperties) { +function openFrames(vhost, searchParams, credentials, extraClientProperties) { if (!vhost) vhost = '/'; else vhost = QS.unescape(vhost); - var query = query || {}; + var searchParams = searchParams || new URLSearchParams(); function intOrDefault(val, def) { - return (val === undefined) ? def : parseInt(val); + return (val === null) ? def : parseInt(val); } var clientProperties = Object.create(CLIENT_PROPERTIES); @@ -62,12 +61,12 @@ function openFrames(vhost, query, credentials, extraClientProperties) { 'clientProperties': copyInto(extraClientProperties, clientProperties), 'mechanism': credentials.mechanism, 'response': credentials.response(), - 'locale': query.locale || 'en_US', + 'locale': searchParams.get('locale') || 'en_US', // tune-ok - 'channelMax': intOrDefault(query.channelMax, 0), - 'frameMax': intOrDefault(query.frameMax, 0x1000), - 'heartbeat': intOrDefault(query.heartbeat, 0), + 'channelMax': intOrDefault(searchParams.get('channelMax'), 0), + 'frameMax': intOrDefault(searchParams.get('frameMax'), 0x1000), + 'heartbeat': intOrDefault(searchParams.get('heartbeat'), 0), // open 'virtualHost': vhost, @@ -104,7 +103,7 @@ function connect(url, socketOptions, openCallback) { var protocol, fields; if (typeof url === 'object') { - protocol = (url.protocol || 'amqp') + ':'; + protocol = url.protocol || 'amqp:'; sockopts.host = url.hostname; sockopts.servername = url.hostname; sockopts.port = url.port || ((protocol === 'amqp:') ? 5672 : 5671); @@ -112,29 +111,22 @@ function connect(url, socketOptions, openCallback) { var user, pass; // Only default if both are missing, to have the same behaviour as // the stringly URL. - if (url.username == undefined && url.password == undefined) { + if (!url.username && !url.password) { user = 'guest'; pass = 'guest'; } else { user = url.username || ''; pass = url.password || ''; } - var config = { - locale: url.locale, - channelMax: url.channelMax, - frameMax: url.frameMax, - heartbeat: url.heartbeat, - }; - - fields = openFrames(url.vhost, config, sockopts.credentials || credentials.plain(user, pass), extraClientProperties); + fields = openFrames(url.vhost, url.searchParams, sockopts.credentials || credentials.plain(user, pass), extraClientProperties); } else { - var parts = URL(url, true); // yes, parse the query string + var parts = new URL(url); protocol = parts.protocol; sockopts.host = parts.hostname; sockopts.servername = parts.hostname; sockopts.port = parseInt(parts.port) || ((protocol === 'amqp:') ? 5672 : 5671); var vhost = parts.pathname ? parts.pathname.substr(1) : null; - fields = openFrames(vhost, parts.query, sockopts.credentials || credentialsFromUrl(parts), extraClientProperties); + fields = openFrames(vhost, parts.searchParams, sockopts.credentials || credentialsFromUrl(parts), extraClientProperties); } var sockok = false; diff --git a/package-lock.json b/package-lock.json index decc1139..04e78707 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,13 +6,12 @@ "packages": { "": { "name": "amqplib", - "version": "0.9.1", + "version": "0.10.0", "license": "MIT", "dependencies": { "bitsyntax": "~0.1.0", "buffer-more-ints": "~1.0.0", - "readable-stream": "1.x >=1.1.9", - "url-parse": "~1.5.10" + "readable-stream": "1.x >=1.1.9" }, "devDependencies": { "claire": "0.4.1", @@ -2258,11 +2257,6 @@ "node": ">=8" } }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" - }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -2331,11 +2325,6 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" - }, "node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -2686,15 +2675,6 @@ "dev": true, "optional": true }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, "node_modules/uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", @@ -4571,11 +4551,6 @@ "fromentries": "^1.2.0" } }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" - }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -4632,11 +4607,6 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" - }, "resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -4903,15 +4873,6 @@ "dev": true, "optional": true }, - "url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", diff --git a/package.json b/package.json index 867620a4..5ca03f39 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,7 @@ "dependencies": { "bitsyntax": "~0.1.0", "buffer-more-ints": "~1.0.0", - "readable-stream": "1.x >=1.1.9", - "url-parse": "~1.5.10" + "readable-stream": "1.x >=1.1.9" }, "devDependencies": { "claire": "0.4.1", diff --git a/test/connect.js b/test/connect.js index fcfd5c01..996bb35a 100644 --- a/test/connect.js +++ b/test/connect.js @@ -6,14 +6,14 @@ var defs = require('../lib/defs'); var assert = require('assert'); var util = require('./util'); var net = require('net'); +var parseUrl = require('url').parse; var fail = util.fail, succeed = util.succeed, latch = util.latch, kCallback = util.kCallback, succeedIfAttributeEquals = util.succeedIfAttributeEquals; var format = require('util').format; -var URL = process.env.URL || 'amqp://localhost'; +var baseURL = process.env.URL || 'amqp://localhost'; -var urlparse = require('url-parse'); suite("Credentials", function() { @@ -29,27 +29,27 @@ suite("Credentials", function() { } test("no creds", function(done) { - var parts = urlparse('amqp://localhost'); + var parts = new URL('amqp://localhost'); var creds = credentialsFromUrl(parts); checkCreds(creds, 'guest', 'guest', done); }); test("usual user:pass", function(done) { - var parts = urlparse('amqp://user:pass@localhost') + var parts = new URL('amqp://user:pass@localhost') var creds = credentialsFromUrl(parts); checkCreds(creds, 'user', 'pass', done); }); test("missing user", function(done) { - var parts = urlparse('amqps://:password@localhost'); + var parts = new URL('amqps://:password@localhost'); var creds = credentialsFromUrl(parts); checkCreds(creds, '', 'password', done); }); test("missing password", function(done) { - var parts = urlparse('amqps://username:@localhost'); + var parts = new URL('amqps://username:@localhost'); var creds = credentialsFromUrl(parts); checkCreds(creds, 'username', '', done); }); test("escaped colons", function(done) { - var parts = urlparse('amqp://user%3Aname:pass%3Aword@localhost') + var parts = new URL('amqp://user%3Aname:pass%3Aword@localhost') var creds = credentialsFromUrl(parts); checkCreds(creds, 'user:name', 'pass:word', done); }); @@ -69,83 +69,72 @@ suite("Connect API", function() { }); }); - test("wrongly typed open option", function(done) { - var url = require('url'); - var parts = url.parse(URL, true); - var q = parts.query || {}; - q.frameMax = 'NOT A NUMBER'; - parts.query = q; - var u = url.format(parts); - connect(u, {}, kCallback(fail(done), succeed(done))); - }); - - test("serverProperties", function(done) { - var url = require('url'); - var parts = url.parse(URL, true); - var config = parts.query || {}; - connect(config, {}, function(err, connection) { - if (err) { return done(err); } - assert.equal(connection.serverProperties.product, 'RabbitMQ'); - done(); - }); - }); + [ + ["As instance of URL", url => url ], + ["As string", url => url.href ], + ].forEach(([suiteDescription, processURL]) => { + suite(suiteDescription, () => { + test("wrongly typed open option", function(done) { + var url = new URL(baseURL); + url.searchParams.set('frameMax', 'NOT A NUMBER'); + connect(processURL(url), {}, kCallback(fail(done), succeed(done))); + }); - test("using custom heartbeat option", function(done) { - var url = require('url'); - var parts = url.parse(URL, true); - var config = parts.query || {}; - config.heartbeat = 20; - connect(config, {}, kCallback(succeedIfAttributeEquals('heartbeat', 20, done), fail(done))); - }); + test("serverProperties", function(done) { + var url = new URL(baseURL); + connect(processURL(url), {}, function(err, connection) { + if (err) { return done(err); } + assert.equal(connection.serverProperties.product, 'RabbitMQ'); + done(); + }); + }); - test("wrongly typed heartbeat option", function(done) { - var url = require('url'); - var parts = url.parse(URL, true); - var config = parts.query || {}; - config.heartbeat = 'NOT A NUMBER'; - connect(config, {}, kCallback(fail(done), succeed(done))); - }); + test("using custom heartbeat option", function(done) { + var url = new URL(baseURL); + url.searchParams.set('heartbeat', 20); + connect(processURL(url), {}, kCallback(succeedIfAttributeEquals('heartbeat', 20, done), fail(done))); + }); - test("using plain credentials", function(done) { - var url = require('url'); - var parts = url.parse(URL, true); - var u = 'guest', p = 'guest'; - if (parts.auth) { - var auth = parts.auth.split(":"); - u = auth[0], p = auth[1]; - } - connect(URL, {credentials: require('../lib/credentials').plain(u, p)}, - kCallback(succeed(done), fail(done))); - }); + test("wrongly typed heartbeat option", function(done) { + var url = new URL(baseURL); + url.searchParams.set('heartbeat', 'NOT A NUMBER'); + connect(processURL(url), {}, kCallback(fail(done), succeed(done))); + }); - test("using amqplain credentials", function(done) { - var url = require('url'); - var parts = url.parse(URL, true); - var u = 'guest', p = 'guest'; - if (parts.auth) { - var auth = parts.auth.split(":"); - u = auth[0], p = auth[1]; - } - connect(URL, {credentials: require('../lib/credentials').amqplain(u, p)}, - kCallback(succeed(done), fail(done))); - }); + test("using plain credentials", function(done) { + var url = new URL(baseURL); + var u = url.username || 'guest'; + var p = url.password || 'guest'; + connect(processURL(url), {credentials: require('../lib/credentials').plain(u, p)}, + kCallback(succeed(done), fail(done))); + }); - test("using unsupported mechanism", function(done) { - var creds = { - mechanism: 'UNSUPPORTED', - response: function() { return Buffer.from(''); } - }; - connect(URL, {credentials: creds}, - kCallback(fail(done), succeed(done))); - }); + test("using amqplain credentials", function(done) { + var url = new URL(baseURL); + var u = url.username || 'guest'; + var p = url.password || 'guest'; + connect(processURL(url), {credentials: require('../lib/credentials').amqplain(u, p)}, + kCallback(succeed(done), fail(done))); + }); - test("with a given connection timeout", function(done) { - var timeoutServer = net.createServer(function() {}).listen(31991); + test("using unsupported mechanism", function(done) { + var creds = { + mechanism: 'UNSUPPORTED', + response: function() { return Buffer.from(''); } + }; + connect(processURL(baseURL), {credentials: creds}, + kCallback(fail(done), succeed(done))); + }); - connect('amqp://localhost:31991', {timeout: 50}, function(err, val) { - timeoutServer.close(); - if (val) done(new Error('Expected connection timeout, did not')); - else done(); + test("with a given connection timeout", function(done) { + var timeoutServer = net.createServer(function() {}).listen(31991); + var url = new URL('amqp://localhost:31991'); + connect(processURL(url), {timeout: 50}, function(err, val) { + timeoutServer.close(); + if (val) done(new Error('Expected connection timeout, did not')); + else done(); + }); + }); }); }); });