Socket
Socket
Sign inDemoInstall

https-proxy-agent

Package Overview
Dependencies
5
Maintainers
1
Versions
34
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 2.2.3 to 2.2.4

.editorconfig

36

index.d.ts
declare module 'https-proxy-agent' {
import * as https from 'https'
import * as https from 'https';
namespace HttpsProxyAgent {
interface HttpsProxyAgentOptions {
host: string
port: number | string
secureProxy?: boolean
headers?: {
[key: string]: string
}
[key: string]: any
}
}
// HttpsProxyAgent doesnt *actually* extend https.Agent, but for my purposes I want it to pretend that it does
class HttpsProxyAgent extends https.Agent {
constructor(opts: HttpsProxyAgent.HttpsProxyAgentOptions | string)
}
namespace HttpsProxyAgent {
interface HttpsProxyAgentOptions {
host: string;
port: number | string;
secureProxy?: boolean;
headers?: {
[key: string]: string;
};
[key: string]: any;
}
}
export = HttpsProxyAgent
// HttpsProxyAgent doesnt *actually* extend https.Agent, but for my purposes I want it to pretend that it does
class HttpsProxyAgent extends https.Agent {
constructor(opts: HttpsProxyAgent.HttpsProxyAgentOptions | string);
}
export = HttpsProxyAgent;
}

@@ -8,3 +8,3 @@ /**

var url = require('url');
var events = require('events');
var assert = require('assert');
var Agent = require('agent-base');

@@ -28,36 +28,38 @@ var inherits = require('util').inherits;

function HttpsProxyAgent(opts) {
if (!(this instanceof HttpsProxyAgent)) return new HttpsProxyAgent(opts);
if ('string' == typeof opts) opts = url.parse(opts);
if (!opts)
throw new Error(
'an HTTP(S) proxy server `host` and `port` must be specified!'
);
debug('creating new HttpsProxyAgent instance: %o', opts);
Agent.call(this, opts);
if (!(this instanceof HttpsProxyAgent)) return new HttpsProxyAgent(opts);
if ('string' == typeof opts) opts = url.parse(opts);
if (!opts)
throw new Error(
'an HTTP(S) proxy server `host` and `port` must be specified!'
);
debug('creating new HttpsProxyAgent instance: %o', opts);
Agent.call(this, opts);
var proxy = Object.assign({}, opts);
var proxy = Object.assign({}, opts);
// if `true`, then connect to the proxy server over TLS. defaults to `false`.
this.secureProxy = proxy.protocol ? /^https:?$/i.test(proxy.protocol) : false;
// if `true`, then connect to the proxy server over TLS. defaults to `false`.
this.secureProxy = proxy.protocol
? /^https:?$/i.test(proxy.protocol)
: false;
// prefer `hostname` over `host`, and set the `port` if needed
proxy.host = proxy.hostname || proxy.host;
proxy.port = +proxy.port || (this.secureProxy ? 443 : 80);
// prefer `hostname` over `host`, and set the `port` if needed
proxy.host = proxy.hostname || proxy.host;
proxy.port = +proxy.port || (this.secureProxy ? 443 : 80);
// ALPN is supported by Node.js >= v5.
// attempt to negotiate http/1.1 for proxy servers that support http/2
if (this.secureProxy && !('ALPNProtocols' in proxy)) {
proxy.ALPNProtocols = ['http 1.1']
}
// ALPN is supported by Node.js >= v5.
// attempt to negotiate http/1.1 for proxy servers that support http/2
if (this.secureProxy && !('ALPNProtocols' in proxy)) {
proxy.ALPNProtocols = ['http 1.1'];
}
if (proxy.host && proxy.path) {
// if both a `host` and `path` are specified then it's most likely the
// result of a `url.parse()` call... we need to remove the `path` portion so
// that `net.connect()` doesn't attempt to open that as a unix socket file.
delete proxy.path;
delete proxy.pathname;
}
if (proxy.host && proxy.path) {
// if both a `host` and `path` are specified then it's most likely the
// result of a `url.parse()` call... we need to remove the `path` portion so
// that `net.connect()` doesn't attempt to open that as a unix socket file.
delete proxy.path;
delete proxy.pathname;
}
this.proxy = proxy;
this.defaultPort = 443;
this.proxy = proxy;
this.defaultPort = 443;
}

@@ -73,157 +75,155 @@ inherits(HttpsProxyAgent, Agent);

HttpsProxyAgent.prototype.callback = function connect(req, opts, fn) {
var proxy = this.proxy;
var proxy = this.proxy;
// create a socket connection to the proxy server
var socket;
if (this.secureProxy) {
socket = tls.connect(proxy);
} else {
socket = net.connect(proxy);
}
// create a socket connection to the proxy server
var socket;
if (this.secureProxy) {
socket = tls.connect(proxy);
} else {
socket = net.connect(proxy);
}
// we need to buffer any HTTP traffic that happens with the proxy before we get
// the CONNECT response, so that if the response is anything other than an "200"
// response code, then we can re-play the "data" events on the socket once the
// HTTP parser is hooked up...
var buffers = [];
var buffersLength = 0;
// we need to buffer any HTTP traffic that happens with the proxy before we get
// the CONNECT response, so that if the response is anything other than an "200"
// response code, then we can re-play the "data" events on the socket once the
// HTTP parser is hooked up...
var buffers = [];
var buffersLength = 0;
function read() {
var b = socket.read();
if (b) ondata(b);
else socket.once('readable', read);
}
function read() {
var b = socket.read();
if (b) ondata(b);
else socket.once('readable', read);
}
function cleanup() {
socket.removeListener('end', onend);
socket.removeListener('error', onerror);
socket.removeListener('close', onclose);
socket.removeListener('readable', read);
}
function cleanup() {
socket.removeListener('end', onend);
socket.removeListener('error', onerror);
socket.removeListener('close', onclose);
socket.removeListener('readable', read);
}
function onclose(err) {
debug('onclose had error %o', err);
}
function onclose(err) {
debug('onclose had error %o', err);
}
function onend() {
debug('onend');
}
function onend() {
debug('onend');
}
function onerror(err) {
cleanup();
fn(err);
}
function onerror(err) {
cleanup();
fn(err);
}
function ondata(b) {
buffers.push(b);
buffersLength += b.length;
var buffered = Buffer.concat(buffers, buffersLength);
var str = buffered.toString('ascii');
function ondata(b) {
buffers.push(b);
buffersLength += b.length;
var buffered = Buffer.concat(buffers, buffersLength);
var str = buffered.toString('ascii');
if (!~str.indexOf('\r\n\r\n')) {
// keep buffering
debug('have not received end of HTTP headers yet...');
read();
return;
}
if (!~str.indexOf('\r\n\r\n')) {
// keep buffering
debug('have not received end of HTTP headers yet...');
read();
return;
}
var firstLine = str.substring(0, str.indexOf('\r\n'));
var statusCode = +firstLine.split(' ')[1];
debug('got proxy server response: %o', firstLine);
var firstLine = str.substring(0, str.indexOf('\r\n'));
var statusCode = +firstLine.split(' ')[1];
debug('got proxy server response: %o', firstLine);
if (200 == statusCode) {
// 200 Connected status code!
var sock = socket;
if (200 == statusCode) {
// 200 Connected status code!
var sock = socket;
// nullify the buffered data since we won't be needing it
buffers = buffered = null;
// nullify the buffered data since we won't be needing it
buffers = buffered = null;
if (opts.secureEndpoint) {
// since the proxy is connecting to an SSL server, we have
// to upgrade this socket connection to an SSL connection
debug(
'upgrading proxy-connected socket to TLS connection: %o',
opts.host
);
opts.socket = socket;
opts.servername = opts.servername || opts.host;
opts.host = null;
opts.hostname = null;
opts.port = null;
sock = tls.connect(opts);
}
if (opts.secureEndpoint) {
// since the proxy is connecting to an SSL server, we have
// to upgrade this socket connection to an SSL connection
debug(
'upgrading proxy-connected socket to TLS connection: %o',
opts.host
);
opts.socket = socket;
opts.servername = opts.servername || opts.host;
opts.host = null;
opts.hostname = null;
opts.port = null;
sock = tls.connect(opts);
}
cleanup();
req.once('socket', resume);
fn(null, sock);
} else {
// some other status code that's not 200... need to re-play the HTTP header
// "data" events onto the socket once the HTTP machinery is attached so
// that the node core `http` can parse and handle the error status code
cleanup();
cleanup();
req.once('socket', resume);
fn(null, sock);
} else {
// some other status code that's not 200... need to re-play the HTTP header
// "data" events onto the socket once the HTTP machinery is attached so
// that the node core `http` can parse and handle the error status code
cleanup();
// the original socket is closed, and a "fake socket" EventEmitter is
// returned instead, so that the proxy doesn't get the HTTP request
// written to it (which may contain `Authorization` headers or other
// sensitive data).
//
// See: https://hackerone.com/reports/541502
socket.destroy();
socket = new events.EventEmitter();
// the original socket is closed, and a new closed socket is
// returned instead, so that the proxy doesn't get the HTTP request
// written to it (which may contain `Authorization` headers or other
// sensitive data).
//
// See: https://hackerone.com/reports/541502
socket.destroy();
socket = new net.Socket();
socket.readable = true;
// save a reference to the concat'd Buffer for the `onsocket` callback
buffers = buffered;
// need to wait for the "socket" event to re-play the "data" events
req.once('socket', onsocket);
// save a reference to the concat'd Buffer for the `onsocket` callback
buffers = buffered;
fn(null, socket);
}
}
// need to wait for the "socket" event to re-play the "data" events
req.once('socket', onsocket);
function onsocket(socket) {
debug('replaying proxy buffer for failed request');
fn(null, socket);
}
}
// replay the "buffers" Buffer onto the `socket`, since at this point
// the HTTP module machinery has been hooked up for the user
if (socket.listenerCount('data') > 0) {
socket.emit('data', buffers);
} else {
// never?
throw new Error('should not happen...');
}
function onsocket(socket) {
debug('replaying proxy buffer for failed request');
assert(socket.listenerCount('data') > 0);
// nullify the cached Buffer instance
buffers = null;
}
// replay the "buffers" Buffer onto the `socket`, since at this point
// the HTTP module machinery has been hooked up for the user
socket.push(buffers);
socket.on('error', onerror);
socket.on('close', onclose);
socket.on('end', onend);
// nullify the cached Buffer instance
buffers = null;
}
read();
socket.on('error', onerror);
socket.on('close', onclose);
socket.on('end', onend);
var hostname = opts.host + ':' + opts.port;
var msg = 'CONNECT ' + hostname + ' HTTP/1.1\r\n';
read();
var headers = Object.assign({}, proxy.headers);
if (proxy.auth) {
headers['Proxy-Authorization'] =
'Basic ' + Buffer.from(proxy.auth).toString('base64');
}
var hostname = opts.host + ':' + opts.port;
var msg = 'CONNECT ' + hostname + ' HTTP/1.1\r\n';
// the Host header should only include the port
// number when it is a non-standard port
var host = opts.host;
if (!isDefaultPort(opts.port, opts.secureEndpoint)) {
host += ':' + opts.port;
}
headers['Host'] = host;
var headers = Object.assign({}, proxy.headers);
if (proxy.auth) {
headers['Proxy-Authorization'] =
'Basic ' + Buffer.from(proxy.auth).toString('base64');
}
headers['Connection'] = 'close';
Object.keys(headers).forEach(function(name) {
msg += name + ': ' + headers[name] + '\r\n';
});
// the Host header should only include the port
// number when it is a non-standard port
var host = opts.host;
if (!isDefaultPort(opts.port, opts.secureEndpoint)) {
host += ':' + opts.port;
}
headers['Host'] = host;
socket.write(msg + '\r\n');
headers['Connection'] = 'close';
Object.keys(headers).forEach(function(name) {
msg += name + ': ' + headers[name] + '\r\n';
});
socket.write(msg + '\r\n');
};

@@ -239,7 +239,7 @@

function resume(socket) {
socket.resume();
socket.resume();
}
function isDefaultPort(port, secure) {
return Boolean((!secure && port === 80) || (secure && port === 443));
return Boolean((!secure && port === 80) || (secure && port === 443));
}
{
"name": "https-proxy-agent",
"version": "2.2.3",
"version": "2.2.4",
"description": "An HTTP(s) proxy `http.Agent` implementation for HTTPS",

@@ -5,0 +5,0 @@ "main": "./index.js",

SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc