Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/blue-buses-build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'https-proxy-agent': minor
---

Emit "proxyConnect" event on HTTP `request` object (part of #153)
7 changes: 4 additions & 3 deletions packages/https-proxy-agent/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import assert from 'assert';
import createDebug from 'debug';
import { OutgoingHttpHeaders } from 'http';
import { Agent, AgentConnectOpts } from 'agent-base';
import parseProxyResponse from './parse-proxy-response';
import { parseProxyResponse } from './parse-proxy-response';

const debug = createDebug('https-proxy-agent');

Expand Down Expand Up @@ -130,9 +130,10 @@ export class HttpsProxyAgent<Uri extends string> extends Agent {

socket.write(`${payload}\r\n`);

const { statusCode, buffered } = await proxyResponsePromise;
const { connect, buffered } = await proxyResponsePromise;
req.emit('proxyConnect', connect);

if (statusCode === 200) {
if (connect.statusCode === 200) {
req.once('socket', resume);

if (opts.secureEndpoint) {
Expand Down
48 changes: 37 additions & 11 deletions packages/https-proxy-agent/src/parse-proxy-response.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import createDebug from 'debug';
import { IncomingHttpHeaders } from 'http';
import { Readable } from 'stream';

const debug = createDebug('https-proxy-agent:parse-proxy-response');

export interface ProxyResponse {
export interface ConnectResponse {
statusCode: number;
buffered: Buffer;
statusText: string;
headers: IncomingHttpHeaders;
}

export default function parseProxyResponse(
export function parseProxyResponse(
socket: Readable
): Promise<ProxyResponse> {
): Promise<{ connect: ConnectResponse; buffered: Buffer }> {
return new Promise((resolve, reject) => {
// 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"
Expand Down Expand Up @@ -60,16 +62,40 @@ export default function parseProxyResponse(
return;
}

const firstLine = buffered.toString(
'ascii',
0,
buffered.indexOf('\r\n')
);
const statusCode = +firstLine.split(' ')[1];
const headerParts = buffered.toString('ascii').split('\r\n');
const firstLine = headerParts.shift();
if (!firstLine) {
throw new Error('No header received');
}
const firstLineParts = firstLine.split(' ');
const statusCode = +firstLineParts[1];
const statusText = firstLineParts.slice(2).join(' ');
const headers: IncomingHttpHeaders = {};
for (const header of headerParts) {
if (!header) continue;
const firstColon = header.indexOf(':');
if (firstColon === -1) {
throw new Error(`Invalid header: "${header}"`);
}
const key = header.slice(0, firstColon).toLowerCase();
const value = header.slice(firstColon + 1).trimStart();
const current = headers[key];
if (typeof current === 'string') {
headers[key] = [current, value];
} else if (Array.isArray(current)) {
current.push(value);
} else {
headers[key] = value;
}
}
debug('got proxy server response: %o', firstLine);
cleanup();
resolve({
statusCode,
connect: {
statusCode,
statusText,
headers,
},
buffered,
});
}
Expand Down
8 changes: 7 additions & 1 deletion packages/https-proxy-agent/test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,13 @@ describe('HttpsProxyAgent', () => {

const agent = new HttpsProxyAgent(proxyUrl);

const res = await req(serverUrl, { agent });
const r = req(serverUrl, { agent });
const [connect] = await once(r, 'proxyConnect');
expect(connect.statusCode).toEqual(200);
expect(connect.statusText).toEqual('Connection established');
expect('date' in connect.headers).toBe(true);

const res = await r;
const body = await json(res);
assert.equal(serverUrl.host, body.host);
});
Expand Down