Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: TooTallNate/proxy-agents
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: https-proxy-agent@6.2.1
Choose a base ref
...
head repository: TooTallNate/proxy-agents
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: https-proxy-agent@7.0.0
Choose a head ref
  • 9 commits
  • 26 files changed
  • 3 contributors

Commits on May 24, 2023

  1. 1
    Copy the full SHA
    d5f3d3f View commit details
  2. 1
    Copy the full SHA
    da699b1 View commit details
  3. Use pnpm publish -r to publish packages (#189)

    Following the instructions here: https://pnpm.io/using-changesets
    TooTallNate authored May 24, 2023
    1

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    b9ac154 View commit details
  4. [http-proxy-agent] Fix keepAlive: true (#190)

    Based on #169.
    
    Co-authored-by: Joe Portner <5295965+jportner@users.noreply.github.com>
    TooTallNate and jportner authored May 24, 2023
    1
    Copy the full SHA
    eb6906b View commit details
  5. 1
    Copy the full SHA
    d2d03d5 View commit details
  6. 1
    Copy the full SHA
    b3860aa View commit details

Commits on May 25, 2023

  1. Revert "Use pnpm publish -r to publish packages (#189)"

    This reverts commit b9ac154.
    TooTallNate committed May 25, 2023
    1
    Copy the full SHA
    a17014f View commit details
  2. 1
    Copy the full SHA
    4a45593 View commit details
  3. 1
    Copy the full SHA
    a90baa5 View commit details
6 changes: 6 additions & 0 deletions packages/agent-base/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# agent-base

## 7.1.0

### Minor Changes

- da699b1: Add `isSecureEndpoint()` as an instance method

## 7.0.2

### Patch Changes
4 changes: 2 additions & 2 deletions packages/agent-base/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "agent-base",
"version": "7.0.2",
"version": "7.1.0",
"description": "Turn a function into an `http.Agent` instance",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -36,7 +36,7 @@
"@types/node": "^14.18.45",
"@types/semver": "^7.3.13",
"@types/ws": "^6.0.4",
"async-listen": "^2.1.0",
"async-listen": "^3.0.0",
"jest": "^29.5.0",
"ts-jest": "^29.1.0",
"tsconfig": "workspace:*",
79 changes: 40 additions & 39 deletions packages/agent-base/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,10 @@
import * as net from 'net';
import * as tls from 'tls';
import * as http from 'http';
import { Duplex } from 'stream';
import type { Duplex } from 'stream';

export * from './helpers';

function isSecureEndpoint(): boolean {
const { stack } = new Error();
if (typeof stack !== 'string') return false;
return stack
.split('\n')
.some(
(l) =>
l.indexOf('(https.js:') !== -1 ||
l.indexOf('node:https:') !== -1
);
}

interface HttpConnectOpts extends net.TcpNetConnectOpts {
secureEndpoint: false;
protocol?: string;
@@ -55,37 +43,49 @@ export abstract class Agent extends http.Agent {
options: AgentConnectOpts
): Promise<Duplex | http.Agent> | Duplex | http.Agent;

createSocket(
req: http.ClientRequest,
options: AgentConnectOpts,
cb: (err: Error | null, s?: Duplex) => void
) {
// Need to determine whether this is an `http` or `https` request.
// First check the `secureEndpoint` property explicitly, since this
// means that a parent `Agent` is "passing through" to this instance.
let secureEndpoint =
typeof options.secureEndpoint === 'boolean'
? options.secureEndpoint
: undefined;

// If no explicit `secure` endpoint, check if `protocol` property is
// set. This will usually be the case since using a full string URL
// or `URL` instance should be the most common case.
if (
typeof secureEndpoint === 'undefined' &&
typeof options.protocol === 'string'
) {
secureEndpoint = options.protocol === 'https:';
/**
* Determine whether this is an `http` or `https` request.
*/
isSecureEndpoint(options?: AgentConnectOpts): boolean {
if (options) {
// First check the `secureEndpoint` property explicitly, since this
// means that a parent `Agent` is "passing through" to this instance.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (typeof (options as any).secureEndpoint === 'boolean') {
return options.secureEndpoint;
}

// If no explicit `secure` endpoint, check if `protocol` property is
// set. This will usually be the case since using a full string URL
// or `URL` instance should be the most common usage.
if (typeof options.protocol === 'string') {
return options.protocol === 'https:';
}
}

// Finally, if no `protocol` property was set, then fall back to
// checking the stack trace of the current call stack, and try to
// detect the "https" module.
if (typeof secureEndpoint === 'undefined') {
secureEndpoint = isSecureEndpoint();
}
const { stack } = new Error();
if (typeof stack !== 'string') return false;
return stack
.split('\n')
.some(
(l) =>
l.indexOf('(https.js:') !== -1 ||
l.indexOf('node:https:') !== -1
);
}

const connectOpts = { ...options, secureEndpoint };
createSocket(
req: http.ClientRequest,
options: AgentConnectOpts,
cb: (err: Error | null, s?: Duplex) => void
) {
const connectOpts = {
...options,
secureEndpoint: this.isSecureEndpoint(options),
};
Promise.resolve()
.then(() => this.connect(req, connectOpts))
.then((socket) => {
@@ -125,7 +125,8 @@ export abstract class Agent extends http.Agent {

get protocol(): string {
return (
this[INTERNAL].protocol ?? (isSecureEndpoint() ? 'https:' : 'http:')
this[INTERNAL].protocol ??
(this.isSecureEndpoint() ? 'https:' : 'http:')
);
}

6 changes: 3 additions & 3 deletions packages/agent-base/test/test.ts
Original file line number Diff line number Diff line change
@@ -265,14 +265,14 @@ describe('Agent (TypeScript)', () => {
reqCount1++;
res.end();
});
const addr1 = (await listen(server1)) as URL;
const addr1 = await listen(server1);

const server2 = http.createServer((req, res) => {
expect(req.headers.connection).toEqual('keep-alive');
reqCount2++;
res.end();
});
const addr2 = (await listen(server2)) as URL;
const addr2 = await listen(server2);

try {
const res = await req(new URL('/foo', addr1), { agent });
@@ -479,7 +479,7 @@ describe('Agent (TypeScript)', () => {
gotReq = true;
res.end();
});
const addr = (await listen(server)) as URL;
const addr = await listen(server);

try {
const res = await req(new URL('/foo', addr), {
2 changes: 1 addition & 1 deletion packages/get-uri/package.json
Original file line number Diff line number Diff line change
@@ -40,7 +40,7 @@
"@types/ftpd": "^0.2.35",
"@types/jest": "^29.5.1",
"@types/node": "^14.18.45",
"async-listen": "^2.1.0",
"async-listen": "^3.0.0",
"ftpd": "https://files-jg1s1zt9l.n8.io/ftpd-v0.2.14.tgz",
"jest": "^29.5.0",
"st": "^1.2.2",
16 changes: 16 additions & 0 deletions packages/http-proxy-agent/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# http-proxy-agent

## 7.0.0

### Major Changes

- b3860aa: Remove `secureProxy` getter

It was not meant to be a public property. If you were using it, just use `agent.proxy.protocol === 'https:'` instead.

## 6.1.1

### Patch Changes

- eb6906b: Fix `keepAlive: true`
- Updated dependencies [da699b1]
- agent-base@7.1.0

## 6.1.0

### Minor Changes
6 changes: 3 additions & 3 deletions packages/http-proxy-agent/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "http-proxy-agent",
"version": "6.1.0",
"version": "7.0.0",
"description": "An HTTP(s) proxy `http.Agent` implementation for HTTP",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -27,14 +27,14 @@
"author": "Nathan Rajlich <nathan@tootallnate.net> (http://n8.io/)",
"license": "MIT",
"dependencies": {
"agent-base": "^7.0.2",
"agent-base": "^7.1.0",
"debug": "^4.3.4"
},
"devDependencies": {
"@types/debug": "^4.1.7",
"@types/jest": "^29.5.1",
"@types/node": "^14.18.45",
"async-listen": "^2.1.0",
"async-listen": "^3.0.0",
"jest": "^29.5.0",
"proxy": "workspace:*",
"ts-jest": "^29.1.0",
52 changes: 30 additions & 22 deletions packages/http-proxy-agent/src/index.ts
Original file line number Diff line number Diff line change
@@ -35,10 +35,6 @@ interface HttpProxyAgentClientRequest extends http.ClientRequest {
_implicitHeader(): void;
}

function isHTTPS(protocol?: string | null): boolean {
return typeof protocol === 'string' ? /^https:?$/i.test(protocol) : false;
}

/**
* The `HttpProxyAgent` implements an HTTP Agent subclass that connects
* to the specified "HTTP proxy server" in order to proxy HTTP requests.
@@ -50,10 +46,6 @@ export class HttpProxyAgent<Uri extends string> extends Agent {
proxyHeaders: OutgoingHttpHeaders | (() => OutgoingHttpHeaders);
connectOpts: net.TcpNetConnectOpts & tls.ConnectionOptions;

get secureProxy() {
return isHTTPS(this.proxy.protocol);
}

constructor(proxy: Uri | URL, opts?: HttpProxyAgentOptions<Uri>) {
super(opts);
this.proxy = typeof proxy === 'string' ? new URL(proxy) : proxy;
@@ -67,7 +59,7 @@ export class HttpProxyAgent<Uri extends string> extends Agent {
);
const port = this.proxy.port
? parseInt(this.proxy.port, 10)
: this.secureProxy
: this.proxy.protocol === 'https:'
? 443
: 80;
this.connectOpts = {
@@ -77,12 +69,18 @@ export class HttpProxyAgent<Uri extends string> extends Agent {
};
}

async connect(
addRequest(req: HttpProxyAgentClientRequest, opts: AgentConnectOpts): void {
req._header = null;
this.setRequestProps(req, opts);
// @ts-expect-error `addRequest()` isn't defined in `@types/node`
super.addRequest(req, opts);
}

setRequestProps(
req: HttpProxyAgentClientRequest,
opts: AgentConnectOpts
): Promise<net.Socket> {
): void {
const { proxy } = this;

const protocol = opts.secureEndpoint ? 'https:' : 'http:';
const hostname = req.getHeader('host') || 'localhost';
const base = `${protocol}//${hostname}`;
@@ -96,7 +94,7 @@ export class HttpProxyAgent<Uri extends string> extends Agent {
req.path = String(url);

// Inject the `Proxy-Authorization` header if necessary.
req._header = null;

const headers: OutgoingHttpHeaders =
typeof this.proxyHeaders === 'function'
? this.proxyHeaders()
@@ -121,15 +119,16 @@ export class HttpProxyAgent<Uri extends string> extends Agent {
req.setHeader(name, value);
}
}
}

// Create a socket connection to the proxy server.
let socket: net.Socket;
if (this.secureProxy) {
debug('Creating `tls.Socket`: %o', this.connectOpts);
socket = tls.connect(this.connectOpts);
} else {
debug('Creating `net.Socket`: %o', this.connectOpts);
socket = net.connect(this.connectOpts);
async connect(
req: HttpProxyAgentClientRequest,
opts: AgentConnectOpts
): Promise<net.Socket> {
req._header = null;

if (!req.path.includes('://')) {
this.setRequestProps(req, opts);
}

// At this point, the http ClientRequest's internal `_header` field
@@ -140,7 +139,6 @@ export class HttpProxyAgent<Uri extends string> extends Agent {
debug('Regenerating stored HTTP header string for request');
req._implicitHeader();
if (req.outputData && req.outputData.length > 0) {
// Node >= 12
debug(
'Patching connection write() output buffer with updated header'
);
@@ -151,6 +149,16 @@ export class HttpProxyAgent<Uri extends string> extends Agent {
debug('Output buffer: %o', req.outputData[0].data);
}

// Create a socket connection to the proxy server.
let socket: net.Socket;
if (this.proxy.protocol === 'https:') {
debug('Creating `tls.Socket`: %o', this.connectOpts);
socket = tls.connect(this.connectOpts);
} else {
debug('Creating `net.Socket`: %o', this.connectOpts);
socket = net.connect(this.connectOpts);
}

// Wait for the socket's `connect` event, so that this `callback()`
// function throws instead of the `http` request machinery. This is
// important for i.e. `PacProxyAgent` which determines a failed proxy
Loading