Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

restify-clients

Package Overview
Dependencies
Maintainers
7
Versions
43
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

restify-clients - npm Package Compare versions

Comparing version 2.5.1 to 2.5.2

4

CHANGES.md

@@ -7,2 +7,6 @@ # restify-clients Changelog

## 2.5.2
* #187: fix callback getting invoked more than once causing throw
## 2.5.1

@@ -9,0 +13,0 @@

125

lib/HttpClient.js

@@ -92,2 +92,61 @@ // Copyright 2012 Mark Cavage, Inc. All rights reserved.

/**
* A function that handles the issuing of the raw request through the
* underlying http core modules. This function is used as the target of
* retry/backoff mechanism for retrying on connection timeouts.
*
* The callback provided to this function is invoked with the following
* signature:
* function(err, req) { ... }
* 1) `err` can be any errors triggered before establishing a connection
* (ConnectionTimeout, DNSTimeout, etc)
* 2) If no err, then the connection has been established, and the user must
* listen to req's result event for further next steps.
*
* Once the server begins to send a response following a successful connection
* establishment, the HttpClient emits a `result` event with the following
* signature:
* function(err, res, req) { ... } // yes, res is intentionally first
*
* Some notes:
* * `err` can be a RequestTimeout or an http 4xx/5xx.
* * res can be null in the case of RequestTimeout
*
* In the case of HttpClient, the callback provided to the function here is
* the user provided callback via the public API:
* httpclient.get('/foo', cb); // cb here is the rawRequest's cb
*
* This is intentional as the HttpClient is fairly low level. This means the
* user is responsible for consuming the request object's `data` and `result`
* events.
*
* In the case of the String/JSONClient, the cb is a function internal to those
* client implementations. These two clients handle dealing with the req
* streams, and do not invoke the user provided callback until after the
* `result` event is fired.
*
* In short, the callback should only ever be called once,
* with the two known scenarios:
*
* 1) A ConnectionTimeout/DNSTimeoutError occurs, and connection is never
* established, and the request object is never created
* 2) The connection is established, and the request object is created and
* returned
*
* However, a RequestTimeout can occur after the connection is established -
* which means we should not invoke the callback again (since it's already been
* invoked), and instead pass this error via the `result` event.
*
* This somewhat asymmetrical way of dealing with request errors (sometimes via
* the callback, sometimes via the result event) means that `once` is used to
* paper over multiple invocations of the callback function provided to this
* function. This is not great, and maybe worth revisiting. The `result` event,
* like the callback, should only ever be emitted once.
*
* @private
* @method rawRequest
* @param {Object} opts an options object
* @param {Function} cb user provided callback fn
* @returns {undefined}
*/
function rawRequest(opts, cb) {

@@ -100,3 +159,3 @@ assert.object(opts, 'options');

/* eslint-disable no-param-reassign */
cb = once.strict(cb);
cb = once(cb);
/* eslint-enable no-param-reassign */

@@ -119,6 +178,2 @@

var req;
// flag that captures whether or not user provided callback has been
// invoked yet. this is an alternative to using once() that is more
// explicit.
var cbCalled = false;

@@ -328,6 +383,3 @@ // increment the number of currently inflight requests

// explicit and easier to reason about.
if (cbCalled === false) {
cb(realErr, req);
cbCalled = true;
}
cb(realErr, req);

@@ -368,13 +420,25 @@ process.nextTick(function () {

if (opts.protocol === 'https:' && socket.socket) {
_socket = socket.socket;
}
if (_socket.writable && !_socket._connecting) {
function onConnect() {
startRequestTimeout();
clearTimeout(connectionTimer);
eventTimes.tcpConnectionAt = process.hrtime();
if (opts._keep_alive) {
_socket.setKeepAlive(true);
socket.setKeepAlive(true);
}
// eagerly call the user provided callback here with the request
// obj after we've established a connection. note that it's still
// possible for the request to timeout at this point, but a
// RequestTimeoutError would be triggered through the 'result' event
// and not the callback.
cb(null, req);
return;
}
if (opts.protocol === 'https:' && socket.socket) {
_socket = socket.socket;
}
// if the provided url to connect to is already an IP, preemptively set

@@ -386,2 +450,13 @@ // the remote address.

// before we attach any events to the socket, look to see if the
// socket's `connect` event has already fired. if the _connecting flag
// is false, the connection was established before we were able to
// attach a listener to the event, so return the request. it appears
// that in this scenario, timers for dnsLookup and tlsHandshake would
// be missing.
if (_socket.writable && !_socket._connecting) {
onConnect();
return;
}
// eslint-disable-next-line handle-callback-err

@@ -399,21 +474,3 @@ _socket.once('lookup', function onLookup(err, addr, family, host) {

_socket.once('connect', function onConnect() {
startRequestTimeout();
clearTimeout(connectionTimer);
eventTimes.tcpConnectionAt = process.hrtime();
if (opts._keep_alive) {
_socket.setKeepAlive(true);
socket.setKeepAlive(true);
}
// eagerly call the user provided callback here with the request
// obj after we've established a connection. note that it's still
// possible for the request to timeout at this point, but a
// RequestTimeoutError would be triggered through the 'result' event
// and not the callback.
cb(null, req);
cbCalled = true;
});
_socket.once('connect', onConnect);
});

@@ -420,0 +477,0 @@

{
"name": "restify-clients",
"version": "2.5.1",
"version": "2.5.2",
"main": "lib/index.js",

@@ -5,0 +5,0 @@ "description": "HttpClient, StringClient, and JsonClient extracted from restify",

@@ -655,2 +655,20 @@ # restify-clients

### Cutting a release
In order to release a new version of the restify-clients module, maintainers go
through the following steps:
1. Bump the version number in the `package.json` file according to the changes
made since the latest release.
2. Add a section in the [changelog](CHANGES.md) for the version being released,
and make sure that a separate item is present for each change.
3. Send a pull request with those changes against the master branch.
4. If the PR is approved by at least one other maintainer, merge the changes
using the new version number as the complete commit message. For instance, if
you're releasing version 2.5.1, the commit message should only be "2.5.1",
without the quotes.
5. Once that pull request is merged, pull those changes in the master branch of
your local clone of the Git repoository, run `make cutarelease` and follow the
instructions.
## License

@@ -657,0 +675,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc