amqplib 0.5.1 → 0.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/.npmignore +0 -1
  2. package/CHANGELOG.md +84 -0
  3. package/Makefile +2 -1
  4. package/README.md +4 -4
  5. package/bin/generate-defs.js +723 -0
  6. package/callback_api.js +1 -0
  7. package/channel_api.js +1 -0
  8. package/examples/headers.js +2 -2
  9. package/examples/receive_generator.js +39 -0
  10. package/examples/send_generators.js +1 -1
  11. package/examples/ssl.js +1 -1
  12. package/examples/tutorials/callback_api/emit_log.js +1 -1
  13. package/examples/tutorials/callback_api/emit_log_direct.js +1 -1
  14. package/examples/tutorials/callback_api/emit_log_topic.js +1 -1
  15. package/examples/tutorials/callback_api/new_task.js +1 -1
  16. package/examples/tutorials/callback_api/rpc_client.js +1 -1
  17. package/examples/tutorials/callback_api/rpc_server.js +1 -1
  18. package/examples/tutorials/callback_api/send.js +1 -1
  19. package/examples/tutorials/emit_log.js +1 -1
  20. package/examples/tutorials/emit_log_direct.js +1 -1
  21. package/examples/tutorials/emit_log_topic.js +1 -1
  22. package/examples/tutorials/new_task.js +1 -1
  23. package/examples/tutorials/rpc_client.js +1 -1
  24. package/examples/tutorials/rpc_server.js +1 -1
  25. package/examples/tutorials/send.js +1 -1
  26. package/examples/waitForConfirms.js +1 -1
  27. package/lib/api_args.js +2 -0
  28. package/lib/channel.js +30 -12
  29. package/lib/codec.js +64 -38
  30. package/lib/connect.js +26 -15
  31. package/lib/connection.js +6 -4
  32. package/lib/credentials.js +20 -3
  33. package/lib/defs.js +203 -75
  34. package/lib/frame.js +2 -1
  35. package/package-lock.json +711 -0
  36. package/package.json +11 -9
  37. package/test/callback_api.js +6 -5
  38. package/test/channel.js +88 -75
  39. package/test/channel_api.js +38 -24
  40. package/test/codec.js +48 -9
  41. package/test/connect.js +88 -3
  42. package/test/connection.js +57 -56
  43. package/test/data.js +32 -9
  44. package/test/frame.js +4 -4
  45. package/test/mux.js +10 -6
  46. package/test/util.js +16 -2
package/callback_api.js CHANGED
@@ -19,3 +19,4 @@ function connect(url, options, cb) {
19
19
 
20
20
  module.exports.connect = connect;
21
21
  module.exports.credentials = require('./lib/credentials');
22
+ module.exports.IllegalOperationError = require('./lib/error').IllegalOperationError;
package/channel_api.js CHANGED
@@ -13,3 +13,4 @@ function connect(url, connOptions) {
13
13
 
14
14
  module.exports.connect = connect;
15
15
  module.exports.credentials = require('./lib/credentials');
16
+ module.exports.IllegalOperationError = require('./lib/error').IllegalOperationError;
@@ -37,6 +37,6 @@ function bindAndConsume(ch, ex, q) {
37
37
 
38
38
  function send(ch, ex) {
39
39
  // The headers for a message are given as an option to `publish`:
40
- ch.publish(ex.exchange, '', new Buffer('hello'), {headers: {baz: 'boo'}});
41
- ch.publish(ex.exchange, '', new Buffer('world'), {headers: {foo: 'bar'}});
40
+ ch.publish(ex.exchange, '', Buffer.from('hello'), {headers: {baz: 'boo'}});
41
+ ch.publish(ex.exchange, '', Buffer.from('world'), {headers: {foo: 'bar'}});
42
42
  }
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+
3
+ 'use strict';
4
+ const co = require('co');
5
+ const amqp = require('amqplib');
6
+ const readline = require('readline');
7
+
8
+ co(function* () {
9
+ const myConsumer = (msg) => {
10
+ if (msg !== null) {
11
+ console.log('consuming message %s in generator', JSON.stringify(msg.content.toString()));
12
+ }
13
+ };
14
+ const conn = yield amqp.connect('amqp://localhost');
15
+ try {
16
+ // create a message to consume
17
+ const q = 'hello';
18
+ const msg = 'Hello World!';
19
+ const channel = yield conn.createChannel();
20
+ yield channel.assertQueue(q);
21
+ channel.sendToQueue(q, Buffer.from(msg));
22
+ console.log(" [x] Sent '%s'", msg);
23
+ // consume the message
24
+ yield channel.consume(q, myConsumer, { noAck: true });
25
+ }
26
+ catch (e) {
27
+ throw e;
28
+ }
29
+ }).catch(err => {
30
+ console.warn('Error:', err);
31
+ });
32
+
33
+ const rl = readline.createInterface({
34
+ input: process.stdin,
35
+ output: process.stdout
36
+ });
37
+
38
+ // pend until message is consumed
39
+ rl.question('newline to exit', () => process.exit());
@@ -21,7 +21,7 @@ co(function* () {
21
21
 
22
22
  yield channel.assertQueue(q);
23
23
 
24
- channel.sendToQueue(q, new Buffer(msg));
24
+ channel.sendToQueue(q, Buffer.from(msg));
25
25
 
26
26
  // if message has been nacked, this will result in an error (rejected promise);
27
27
  yield channel.waitForConfirms();
package/examples/ssl.js CHANGED
@@ -59,6 +59,6 @@ var open = amqp.connect('amqps://localhost', opts);
59
59
  open.then(function(conn) {
60
60
  process.on('SIGINT', conn.close.bind(conn));
61
61
  return conn.createChannel().then(function(ch) {
62
- ch.sendToQueue('foo', new Buffer('Hello World!'));
62
+ ch.sendToQueue('foo', Buffer.from('Hello World!'));
63
63
  });
64
64
  }).then(null, console.warn);
@@ -17,7 +17,7 @@ function on_connect(err, conn) {
17
17
  ch.assertExchange(ex, 'fanout', {durable: false});
18
18
  var msg = process.argv.slice(2).join(' ') ||
19
19
  'info: Hello World!';
20
- ch.publish(ex, '', new Buffer(msg));
20
+ ch.publish(ex, '', Buffer.from(msg));
21
21
  console.log(" [x] Sent '%s'", msg);
22
22
  ch.close(function() { conn.close(); });
23
23
  }
@@ -20,7 +20,7 @@ function on_connect(err, conn) {
20
20
  function on_channel_open(err, ch) {
21
21
  if (err !== null) return bail(err, conn);
22
22
  ch.assertExchange(ex, 'direct', exopts, function(err, ok) {
23
- ch.publish(ex, severity, new Buffer(message));
23
+ ch.publish(ex, severity, Buffer.from(message));
24
24
  ch.close(function() { conn.close(); });
25
25
  });
26
26
  }
@@ -17,7 +17,7 @@ function on_connect(err, conn) {
17
17
  conn.createChannel(function(err, ch) {
18
18
  ch.assertExchange(ex, 'topic', exopts, function(err, ok) {
19
19
  if (err !== null) return bail(err, conn);
20
- ch.publish(ex, key, new Buffer(message));
20
+ ch.publish(ex, key, Buffer.from(message));
21
21
  console.log(" [x] Sent %s:'%s'", key, message);
22
22
  ch.close(function() { conn.close(); });
23
23
  });
@@ -17,7 +17,7 @@ function on_connect(err, conn) {
17
17
  ch.assertQueue(q, {durable: true}, function(err, _ok) {
18
18
  if (err !== null) return bail(err, conn);
19
19
  var msg = process.argv.slice(2).join(' ') || "Hello World!";
20
- ch.sendToQueue(q, new Buffer(msg), {persistent: true});
20
+ ch.sendToQueue(q, Buffer.from(msg), {persistent: true});
21
21
  console.log(" [x] Sent '%s'", msg);
22
22
  ch.close(function() { conn.close(); });
23
23
  });
@@ -39,7 +39,7 @@ function on_connect(err, conn) {
39
39
  var queue = ok.queue;
40
40
  ch.consume(queue, maybeAnswer, {noAck:true});
41
41
  console.log(' [x] Requesting fib(%d)', n);
42
- ch.sendToQueue('rpc_queue', new Buffer(n.toString()), {
42
+ ch.sendToQueue('rpc_queue', Buffer.from(n.toString()), {
43
43
  replyTo: queue, correlationId: correlationId
44
44
  });
45
45
  });
@@ -35,7 +35,7 @@ function on_connect(err, conn) {
35
35
  var n = parseInt(msg.content.toString());
36
36
  console.log(' [.] fib(%d)', n);
37
37
  ch.sendToQueue(msg.properties.replyTo,
38
- new Buffer(fib(n).toString()),
38
+ Buffer.from(fib(n).toString()),
39
39
  {correlationId: msg.properties.correlationId});
40
40
  ch.ack(msg);
41
41
  }
@@ -17,7 +17,7 @@ function on_connect(err, conn) {
17
17
  if (err !== null) return bail(err, conn);
18
18
  ch.assertQueue(q, {durable: false}, function(err, ok) {
19
19
  if (err !== null) return bail(err, conn);
20
- ch.sendToQueue(q, new Buffer(msg));
20
+ ch.sendToQueue(q, Buffer.from(msg));
21
21
  console.log(" [x] Sent '%s'", msg);
22
22
  ch.close(function() { conn.close(); });
23
23
  });
@@ -11,7 +11,7 @@ amqp.connect('amqp://localhost').then(function(conn) {
11
11
  'info: Hello World!';
12
12
 
13
13
  return ok.then(function() {
14
- ch.publish(ex, '', new Buffer(message));
14
+ ch.publish(ex, '', Buffer.from(message));
15
15
  console.log(" [x] Sent '%s'", message);
16
16
  return ch.close();
17
17
  });
@@ -12,7 +12,7 @@ amqp.connect('amqp://localhost').then(function(conn) {
12
12
  var ok = ch.assertExchange(ex, 'direct', {durable: false});
13
13
 
14
14
  return ok.then(function() {
15
- ch.publish(ex, severity, new Buffer(message));
15
+ ch.publish(ex, severity, Buffer.from(message));
16
16
  console.log(" [x] Sent %s:'%s'", severity, message);
17
17
  return ch.close();
18
18
  });
@@ -11,7 +11,7 @@ amqp.connect('amqp://localhost').then(function(conn) {
11
11
  var ex = 'topic_logs';
12
12
  var ok = ch.assertExchange(ex, 'topic', {durable: false});
13
13
  return ok.then(function() {
14
- ch.publish(ex, key, new Buffer(message));
14
+ ch.publish(ex, key, Buffer.from(message));
15
15
  console.log(" [x] Sent %s:'%s'", key, message);
16
16
  return ch.close();
17
17
  });
@@ -10,7 +10,7 @@ amqp.connect('amqp://localhost').then(function(conn) {
10
10
 
11
11
  return ok.then(function() {
12
12
  var msg = process.argv.slice(2).join(' ') || "Hello World!";
13
- ch.sendToQueue(q, new Buffer(msg), {deliveryMode: true});
13
+ ch.sendToQueue(q, Buffer.from(msg), {deliveryMode: true});
14
14
  console.log(" [x] Sent '%s'", msg);
15
15
  return ch.close();
16
16
  });
@@ -40,7 +40,7 @@ amqp.connect('amqp://localhost').then(function(conn) {
40
40
 
41
41
  ok = ok.then(function(queue) {
42
42
  console.log(' [x] Requesting fib(%d)', n);
43
- ch.sendToQueue('rpc_queue', new Buffer(n.toString()), {
43
+ ch.sendToQueue('rpc_queue', Buffer.from(n.toString()), {
44
44
  correlationId: corrId, replyTo: queue
45
45
  });
46
46
  });
@@ -31,7 +31,7 @@ amqp.connect('amqp://localhost').then(function(conn) {
31
31
  console.log(' [.] fib(%d)', n);
32
32
  var response = fib(n);
33
33
  ch.sendToQueue(msg.properties.replyTo,
34
- new Buffer(response.toString()),
34
+ Buffer.from(response.toString()),
35
35
  {correlationId: msg.properties.correlationId});
36
36
  ch.ack(msg);
37
37
  }
@@ -15,7 +15,7 @@ amqp.connect('amqp://localhost').then(function(conn) {
15
15
  // (when `false`) that you should wait for the event `'drain'`
16
16
  // to fire before writing again. We're just doing the one write,
17
17
  // so we'll ignore it.
18
- ch.sendToQueue(q, new Buffer(msg));
18
+ ch.sendToQueue(q, Buffer.from(msg));
19
19
  console.log(" [x] Sent '%s'", msg);
20
20
  return ch.close();
21
21
  });
@@ -12,7 +12,7 @@ function mkCallback(i) {
12
12
  amqp.connect().then(function(c) {
13
13
  c.createConfirmChannel().then(function(ch) {
14
14
  for (var i=0; i < NUM_MSGS; i++) {
15
- ch.publish('amq.topic', 'whatever', new Buffer('blah'), {}, mkCallback(i));
15
+ ch.publish('amq.topic', 'whatever', Buffer.from('blah'), {}, mkCallback(i));
16
16
  }
17
17
  ch.waitForConfirms().then(function() {
18
18
  console.log('All messages done');
package/lib/api_args.js CHANGED
@@ -58,6 +58,8 @@ Args.assertQueue = function(queue, options) {
58
58
  options.deadLetterRoutingKey);
59
59
  setIfDefined(argt, 'x-max-length', options.maxLength);
60
60
  setIfDefined(argt, 'x-max-priority', options.maxPriority);
61
+ setIfDefined(argt, 'x-overflow', options.overflow);
62
+ setIfDefined(argt, 'x-queue-mode', options.queueMode);
61
63
 
62
64
  return {
63
65
  queue: queue,
package/lib/channel.js CHANGED
@@ -16,7 +16,7 @@ var EventEmitter = require('events').EventEmitter;
16
16
  var fmt = require('util').format;
17
17
  var IllegalOperationError = require('./error').IllegalOperationError;
18
18
  var stackCapture = require('./error').stackCapture;
19
-
19
+ var Buffer = require('safe-buffer').Buffer
20
20
  function Channel(connection) {
21
21
  EventEmitter.call( this );
22
22
  this.connection = connection;
@@ -33,6 +33,12 @@ function Channel(connection) {
33
33
  this.on('nack', this.handleConfirm.bind(this, function(cb) {
34
34
  if (cb) cb(new Error('message nacked'));
35
35
  }));
36
+ this.on('close', function () {
37
+ var cb;
38
+ while (cb = this.unconfirmed.shift()) {
39
+ if (cb) cb(new Error('channel closed'));
40
+ }
41
+ })
36
42
  // message frame state machine
37
43
  this.handleMessage = acceptDeliveryOrReturn;
38
44
  }
@@ -103,9 +109,10 @@ C._rpc = function(method, fields, expect, cb) {
103
109
  // We have detected a problem, so it's up to us to close the
104
110
  // channel
105
111
  var expectedName = methodName(expect);
112
+
106
113
  var e = new Error(fmt("Expected %s; got %s",
107
114
  expectedName, inspect(f, false)));
108
- self.closeWithError(fmt('Expected %s; got %s',
115
+ self.closeWithError(f.id, fmt('Expected %s; got %s',
109
116
  expectedName, methodName(f.id)),
110
117
  defs.constants.UNEXPECTED_FRAME, e);
111
118
  return cb(e);
@@ -124,7 +131,11 @@ C._rpc = function(method, fields, expect, cb) {
124
131
  ? fmt("Operation failed: %s; %s",
125
132
  methodName(method), closeMsg(err))
126
133
  : fmt("Channel closed by server: %s", closeMsg(err));
127
- return cb(new Error(e));
134
+ var closeFrameError = new Error(e);
135
+ closeFrameError.code = err.fields.replyCode;
136
+ closeFrameError.classId = err.fields.classId;
137
+ closeFrameError.methodId = err.fields.methodId;
138
+ return cb(closeFrameError);
128
139
  }
129
140
  }
130
141
 
@@ -186,7 +197,7 @@ C.toClosing = function(capturedStack, k) {
186
197
  };
187
198
 
188
199
  C._rejectPending = function() {
189
- function rej(r) {
200
+ function rej(r) {
190
201
  r(new Error("Channel ended, no reply will be forthcoming"));
191
202
  }
192
203
  if (this.reply !== null) rej(this.reply);
@@ -210,10 +221,15 @@ C.closeBecause = function(reason, code, k) {
210
221
  // If we close because there's been an error, we need to distinguish
211
222
  // between what we tell the server (`reason`) and what we report as
212
223
  // the cause in the client (`error`).
213
- C.closeWithError = function(reason, code, error) {
224
+ C.closeWithError = function(id, reason, code, error) {
214
225
  var self = this;
215
226
  this.closeBecause(reason, code, function() {
216
227
  error.code = code;
228
+ // content frames and consumer errors do not provide a method a class/method ID
229
+ if (id) {
230
+ error.classId = defs.info(id).classId;
231
+ error.methodId = defs.info(id).methodId;
232
+ }
217
233
  self.emit('error', error);
218
234
  });
219
235
  };
@@ -232,15 +248,15 @@ C.acceptMessageFrame = function(f) {
232
248
  }
233
249
  catch (msg) {
234
250
  if (typeof msg === 'string') {
235
- this.closeWithError(msg, defs.constants.UNEXPECTED_FRAME,
251
+ this.closeWithError(f.id, msg, defs.constants.UNEXPECTED_FRAME,
236
252
  new Error(msg));
237
253
  }
238
254
  else if (msg instanceof Error) {
239
- this.closeWithError('Error while processing message',
255
+ this.closeWithError(f.id, 'Error while processing message',
240
256
  defs.constants.INTERNAL_ERROR, msg);
241
257
  }
242
258
  else {
243
- this.closeWithError('Internal error while processing message',
259
+ this.closeWithError(f.id, 'Internal error while processing message',
244
260
  defs.constants.INTERNAL_ERROR,
245
261
  new Error(msg.toString()));
246
262
  }
@@ -283,15 +299,15 @@ function acceptMessage(continuation) {
283
299
  if (f.id === defs.BasicProperties) {
284
300
  message.properties = f.fields;
285
301
  totalSize = remaining = f.size;
286
-
302
+
287
303
  // for zero-length messages, content frames aren't required.
288
304
  if (totalSize === 0) {
289
- message.content = new Buffer(0);
305
+ message.content = Buffer.alloc(0);
290
306
  continuation(message);
291
307
  return acceptDeliveryOrReturn;
292
308
  }
293
309
  else {
294
- return content;
310
+ return content;
295
311
  }
296
312
  }
297
313
  else {
@@ -405,6 +421,8 @@ C.accept = function(f) {
405
421
 
406
422
  var error = new Error(emsg);
407
423
  error.code = f.fields.replyCode;
424
+ error.classId = f.fields.classId;
425
+ error.methodId = f.fields.methodId;
408
426
  this.emit('error', error);
409
427
 
410
428
  var s = stackCapture(emsg);
@@ -413,7 +431,7 @@ C.accept = function(f) {
413
431
 
414
432
  case defs.BasicFlow:
415
433
  // RabbitMQ doesn't send this, it just blocks the TCP socket
416
- return this.closeWithError("Flow not implemented",
434
+ return this.closeWithError(f.id, "Flow not implemented",
417
435
  defs.constants.NOT_IMPLEMENTED,
418
436
  new Error('Flow not implemented'));
419
437
 
package/lib/codec.js CHANGED
@@ -1,4 +1,4 @@
1
- //
1
+ //
2
2
  //
3
3
  //
4
4
 
@@ -110,6 +110,40 @@ function encodeFieldValue(buffer, value, offset) {
110
110
  type = value['!'];
111
111
  }
112
112
 
113
+ // If it's a JS number, we'll have to guess what type to encode it
114
+ // as.
115
+ if (type == 'number') {
116
+ // Making assumptions about the kind of number (floating point
117
+ // v integer, signed, unsigned, size) desired is dangerous in
118
+ // general; however, in practice RabbitMQ uses only
119
+ // longstrings and unsigned integers in its arguments, and
120
+ // other clients generally conflate number types anyway. So
121
+ // the only distinction we care about is floating point vs
122
+ // integers, preferring integers since those can be promoted
123
+ // if necessary. If floating point is required, we may as well
124
+ // use double precision.
125
+ if (isFloatingPoint(val)) {
126
+ type = 'double';
127
+ }
128
+ else { // only signed values are used in tables by
129
+ // RabbitMQ. It *used* to (< v3.3.0) treat the byte 'b'
130
+ // type as unsigned, but most clients (and the spec)
131
+ // think it's signed, and now RabbitMQ does too.
132
+ if (val < 128 && val >= -128) {
133
+ type = 'byte';
134
+ }
135
+ else if (val >= -0x8000 && val < 0x8000) {
136
+ type = 'short'
137
+ }
138
+ else if (val >= -0x80000000 && val < 0x80000000) {
139
+ type = 'int';
140
+ }
141
+ else {
142
+ type = 'long';
143
+ }
144
+ }
145
+ }
146
+
113
147
  function tag(t) { buffer.write(t, offset); offset++; }
114
148
 
115
149
  switch (type) {
@@ -141,44 +175,36 @@ function encodeFieldValue(buffer, value, offset) {
141
175
  tag('t');
142
176
  buffer.writeUInt8((val) ? 1 : 0, offset); offset++;
143
177
  break;
144
- case 'number':
145
- // Making assumptions about the kind of number (floating point
146
- // v integer, signed, unsigned, size) desired is dangerous in
147
- // general; however, in practice RabbitMQ uses only
148
- // longstrings and unsigned integers in its arguments, and
149
- // other clients generally conflate number types anyway. So
150
- // the only distinction we care about is floating point vs
151
- // integers, preferring integers since those can be promoted
152
- // if necessary. If floating point is required, we may as well
153
- // use double precision.
154
- if (isFloatingPoint(val)) {
155
- tag('d');
156
- buffer.writeDoubleBE(val, offset);
157
- offset += 8;
158
- }
159
- else { // only signed values are used in tables by
160
- // RabbitMQ. It *used* to (< v3.3.0) treat the byte 'b'
161
- // type as unsigned, but most clients (and the spec)
162
- // think it's signed, and now RabbitMQ does too.
163
- if (val < 128 && val >= -128) {
164
- tag('b');
165
- buffer.writeInt8(val, offset); offset++;
166
- }
167
- else if (val >= -0x8000 && val < 0x8000) { // short
168
- tag('s');
169
- buffer.writeInt16BE(val, offset); offset += 2;
170
- }
171
- else if (val >= -0x80000000 && val < 0x80000000) { // int
172
- tag('I');
173
- buffer.writeInt32BE(val, offset); offset += 4;
174
- }
175
- else { // long
176
- tag('l');
177
- ints.writeInt64BE(buffer, val, offset); offset += 8;
178
- }
179
- }
178
+ // These are the types that are either guessed above, or
179
+ // explicitly given using the {'!': type} notation.
180
+ case 'double':
181
+ case 'float64':
182
+ tag('d');
183
+ buffer.writeDoubleBE(val, offset);
184
+ offset += 8;
185
+ break;
186
+ case 'byte':
187
+ case 'int8':
188
+ tag('b');
189
+ buffer.writeInt8(val, offset); offset++;
190
+ break;
191
+ case 'short':
192
+ case 'int16':
193
+ tag('s');
194
+ buffer.writeInt16BE(val, offset); offset += 2;
180
195
  break;
181
- // Now for exotic types, those can only be denoted by using
196
+ case 'int':
197
+ case 'int32':
198
+ tag('I');
199
+ buffer.writeInt32BE(val, offset); offset += 4;
200
+ break;
201
+ case 'long':
202
+ case 'int64':
203
+ tag('l');
204
+ ints.writeInt64BE(buffer, val, offset); offset += 8;
205
+ break;
206
+
207
+ // Now for exotic types, those can _only_ be denoted by using
182
208
  // `{'!': type, value: val}
183
209
  case 'timestamp':
184
210
  tag('T');
package/lib/connect.js CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  'use strict';
8
8
 
9
- var URL = require('url');
9
+ var URL = require('url-parse');
10
10
  var QS = require('querystring');
11
11
  var Connection = require('./connection').Connection;
12
12
  var fmt = require('util').format;
@@ -76,13 +76,12 @@ function openFrames(vhost, query, credentials, extraClientProperties) {
76
76
  };
77
77
  }
78
78
 
79
- // Decide on credentials based on what we're supplied
79
+ // Decide on credentials based on what we're supplied.
80
80
  function credentialsFromUrl(parts) {
81
81
  var user = 'guest', passwd = 'guest';
82
- if (parts.auth) {
83
- var auth = parts.auth.split(':');
84
- user = auth[0];
85
- passwd = auth[1];
82
+ if (parts.username != '' || parts.password != '') {
83
+ user = (parts.username) ? unescape(parts.username) : '';
84
+ passwd = (parts.password) ? unescape(parts.password) : '';
86
85
  }
87
86
  return credentials.plain(user, passwd);
88
87
  }
@@ -110,17 +109,25 @@ function connect(url, socketOptions, openCallback) {
110
109
  sockopts.port = url.port || ((protocol === 'amqp:') ? 5672 : 5671);
111
110
 
112
111
  var user, pass;
113
- if (!url.username) {
114
- user = 'guest';
115
- pass = url.password || 'guest';
112
+ // Only default if both are missing, to have the same behaviour as
113
+ // the stringly URL.
114
+ if (url.username == undefined && url.password == undefined) {
115
+ user = 'guest'; pass = 'guest';
116
116
  } else {
117
- user = url.username;
118
- pass = url.password;
117
+ user = url.username || '';
118
+ pass = url.password || '';
119
119
  }
120
120
 
121
- fields = openFrames(url.vhost, null, sockopts.credentials || credentials.plain(user, pass), extraClientProperties);
121
+ var config = {
122
+ locale: url.locale,
123
+ channelMax: url.channelMax,
124
+ frameMax: url.frameMax,
125
+ heartbeat: url.heartbeat,
126
+ };
127
+
128
+ fields = openFrames(url.vhost, config, sockopts.credentials || credentials.plain(user, pass), extraClientProperties);
122
129
  } else {
123
- var parts = URL.parse(url, true); // yes, parse the query string
130
+ var parts = URL(url, true); // yes, parse the query string
124
131
  protocol = parts.protocol;
125
132
  sockopts.host = parts.hostname;
126
133
  sockopts.port = parseInt(parts.port) || ((protocol === 'amqp:') ? 5672 : 5671);
@@ -159,8 +166,11 @@ function connect(url, socketOptions, openCallback) {
159
166
  }
160
167
 
161
168
  if (timeout) {
162
- sock.setTimeout(
163
- timeout, openCallback.bind(this, new Error('connect ETIMEDOUT')));
169
+ sock.setTimeout(timeout, function() {
170
+ sock.end();
171
+ sock.destroy();
172
+ openCallback(new Error('connect ETIMEDOUT'));
173
+ });
164
174
  }
165
175
 
166
176
  sock.once('error', function(err) {
@@ -170,3 +180,4 @@ function connect(url, socketOptions, openCallback) {
170
180
  }
171
181
 
172
182
  module.exports.connect = connect;
183
+ module.exports.credentialsFromUrl = credentialsFromUrl;
package/lib/connection.js CHANGED
@@ -9,6 +9,7 @@ var constants = defs.constants;
9
9
  var frame = require('./frame');
10
10
  var HEARTBEAT = frame.HEARTBEAT;
11
11
  var Mux = require('./mux').Mux;
12
+ var Buffer = require('safe-buffer').Buffer
12
13
 
13
14
  var Duplex =
14
15
  require('stream').Duplex ||
@@ -43,7 +44,7 @@ function Connection(underlying) {
43
44
  this.muxer = new Mux(stream);
44
45
 
45
46
  // frames
46
- this.rest = new Buffer(0);
47
+ this.rest = Buffer.alloc(0);
47
48
  this.frameMax = constants.FRAME_MIN_SIZE;
48
49
  this.sentSinceLastCheck = false;
49
50
  this.recvSinceLastCheck = false;
@@ -204,6 +205,7 @@ C.open = function(allFields, openCallback0) {
204
205
  allFields.mechanism)));
205
206
  return;
206
207
  }
208
+ self.serverProperties = start.fields.serverProperties;
207
209
  send(defs.ConnectionStartOk);
208
210
  wait(afterStartOk);
209
211
  }
@@ -464,7 +466,7 @@ C.freshChannel = function(channel, options) {
464
466
  C.releaseChannel = function(channel) {
465
467
  this.freeChannels.clear(channel);
466
468
  var buffer = this.channels[channel].buffer;
467
- this.muxer.unpipeFrom(buffer);
469
+ buffer.end(); // will also cause it to be unpiped
468
470
  this.channels[channel] = null;
469
471
  };
470
472
 
@@ -550,7 +552,7 @@ C.sendMessage = function(channel,
550
552
  var allLen = methodHeaderLen + bodyLen;
551
553
 
552
554
  if (allLen < SINGLE_CHUNK_THRESHOLD) {
553
- var all = new Buffer(allLen);
555
+ var all = Buffer.alloc(allLen);
554
556
  var offset = mframe.copy(all, 0);
555
557
  offset += pframe.copy(all, offset);
556
558
 
@@ -560,7 +562,7 @@ C.sendMessage = function(channel,
560
562
  }
561
563
  else {
562
564
  if (methodHeaderLen < SINGLE_CHUNK_THRESHOLD) {
563
- var both = new Buffer(methodHeaderLen);
565
+ var both = Buffer.alloc(methodHeaderLen);
564
566
  var offset = mframe.copy(both, 0);
565
567
  pframe.copy(both, offset);
566
568
  buffer.write(both);
@@ -8,19 +8,36 @@
8
8
  // * PLAIN (send username and password in the plain)
9
9
  // * EXTERNAL (assume the server will figure out who you are from
10
10
  // context, i.e., your SSL certificate)
11
+ var Buffer = require('safe-buffer').Buffer
12
+ var codec = require('./codec')
11
13
 
12
14
  module.exports.plain = function(user, passwd) {
13
15
  return {
14
16
  mechanism: 'PLAIN',
15
17
  response: function() {
16
- return new Buffer(['', user, passwd].join(String.fromCharCode(0)))
17
- }
18
+ return Buffer.from(['', user, passwd].join(String.fromCharCode(0)))
19
+ },
20
+ username: user,
21
+ password: passwd
22
+ }
23
+ }
24
+
25
+ module.exports.amqplain = function(user, passwd) {
26
+ return {
27
+ mechanism: 'AMQPLAIN',
28
+ response: function() {
29
+ const buffer = Buffer.alloc(16384);
30
+ const size = codec.encodeTable(buffer, { LOGIN: user, PASSWORD: passwd}, 0);
31
+ return buffer.slice(4, size);
32
+ },
33
+ username: user,
34
+ password: passwd
18
35
  }
19
36
  }
20
37
 
21
38
  module.exports.external = function() {
22
39
  return {
23
40
  mechanism: 'EXTERNAL',
24
- response: function() { return new Buffer(''); }
41
+ response: function() { return Buffer.from(''); }
25
42
  }
26
43
  }