Reading the ssh2 HTTPAgent Source Code

· 2 min read · 252 Words · -Views -Comments

The ssh2 package ships HTTP agents that intercept requests and forward them through an SSH connection. I recently needed a custom agent, so I dug through the implementation.

The agent lives in lib/http-agents.js:

const { Agent: HttpAgent } = require('http');
const { Agent: HttpsAgent } = require('https');

for (const ctor of [HttpAgent, HttpsAgent]) {
  // ...
  exports[ctor === HttpAgent ? 'SSHTTPAgent' : 'SSHTTPSAgent'] = SSHAgent;
}

A loop adapts Node’s built-in Agent constructors and exports derived classes.

Node’s Agent signature:

new Agent([options])

ssh2’s agent accepts two arguments because it also needs SSH configuration:

constructor(connectCfg, agentOptions) {
  super(agentOptions);

  this._connectCfg = connectCfg;
  this._defaultSrcIP = (agentOptions && agentOptions.srcIP) || 'localhost';
}
  • connectCfg holds SSH connection parameters.
  • agentOptions is passed to Node’s Agent. ssh2 adds srcIP, controlling the source IP for the TCP socket.

createConnection(options, cb) is invoked by the pooling mechanism to obtain a TCP socket. The agent:

  1. Creates an SSH Client and connects using connectCfg.
  2. On ready, calls forwardOut to open a TCP stream.
  3. Calls cb(null, decorateStream(stream, ctor, options)); so the stream exposes the methods expected by HTTP(S) consumers.

Error-handling highlights:

  1. If the TCP communication errors, the error is passed to cb and the SSH client closes.
  2. If the TCP connection closes, the SSH client closes; no error is passed to cb because the closure is expected.

When creating the local endpoint, a port must be bound. If localPort isn’t supplied, it defaults to 0, letting the OS choose an ephemeral port (not literally port 0):

const srcPort = (options && options.localPort) || 0;
Authors
Developer, digital product enthusiast, tinkerer, sharer, open source lover