/
test.ts
237 lines (206 loc) · 6.9 KB
/
test.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
import * as fs from 'fs';
import * as http from 'http';
import * as https from 'https';
import assert from 'assert';
import { once } from 'events';
import { createProxy, ProxyServer } from 'proxy';
import { listen } from 'async-listen';
import { json, req } from 'agent-base';
import { HttpProxyAgent } from '../src';
describe('HttpProxyAgent', () => {
let httpServer: http.Server;
let httpServerUrl: URL;
let proxy: ProxyServer;
let proxyUrl: URL;
let sslProxy: ProxyServer;
let sslProxyUrl: URL;
beforeAll(async () => {
// setup HTTP proxy server
proxy = createProxy();
proxyUrl = await listen(proxy);
});
beforeAll(async () => {
// setup target HTTP server
httpServer = http.createServer();
httpServerUrl = await listen(httpServer);
});
beforeAll(async () => {
// setup SSL HTTP proxy server
const options = {
key: fs.readFileSync(`${__dirname}/ssl-cert-snakeoil.key`),
cert: fs.readFileSync(`${__dirname}/ssl-cert-snakeoil.pem`),
};
sslProxy = createProxy(https.createServer(options));
sslProxyUrl = await listen(sslProxy);
});
beforeEach(() => {
httpServer.removeAllListeners('request');
delete proxy.authenticate;
});
// shut down test HTTP server
afterAll(() => {
proxy.close();
httpServer.close();
sslProxy.close();
});
describe('constructor', () => {
it('should accept a "string" proxy argument', () => {
const agent = new HttpProxyAgent(proxyUrl.href);
assert.equal(proxyUrl.hostname, agent.proxy.hostname);
assert.equal(proxyUrl.port, agent.proxy.port);
});
it('should accept a `URL` instance proxy argument', () => {
const agent = new HttpProxyAgent(proxyUrl);
assert.equal(proxyUrl.hostname, agent.proxy.hostname);
assert.equal(proxyUrl.port, agent.proxy.port);
});
it('should set a `defaultPort` property', () => {
const agent = new HttpProxyAgent(proxyUrl);
assert.equal(80, agent.defaultPort);
});
});
describe('"http" module', () => {
it('should work over an HTTP proxy', async () => {
// set HTTP "request" event handler for this test
httpServer.once('request', (req, res) => {
res.end(JSON.stringify(req.headers));
});
const agent = new HttpProxyAgent(proxyUrl);
const res = await req(httpServerUrl, { agent });
const body = await json(res);
expect(body.host).toEqual(httpServerUrl.host);
assert('via' in body);
});
it('should work over an HTTPS proxy', async () => {
// set HTTP "request" event handler for this test
httpServer.once('request', (req, res) => {
res.end(JSON.stringify(req.headers));
});
const agent = new HttpProxyAgent(sslProxyUrl, {
rejectUnauthorized: false,
});
const res = await req(httpServerUrl, { agent });
const body = await json(res);
expect(body.host).toEqual(httpServerUrl.host);
expect(body).toHaveProperty('via');
});
it('should proxy the query string of the request path', async () => {
// set HTTP "request" event handler for this test
httpServer.once('request', (req, res) => {
res.end(
JSON.stringify({
url: req.url,
})
);
});
const agent = new HttpProxyAgent(proxyUrl);
const path = '/test?foo=bar&1=2';
const res = await req(new URL(path, httpServerUrl), { agent });
const body = await json(res);
expect(body.url).toEqual(path);
});
it('should receive the 407 authorization code on the `http.ClientResponse`', async () => {
// reject all requests
proxy.authenticate = () => false;
const agent = new HttpProxyAgent(proxyUrl);
const res = await req('http://example.com', { agent });
assert.equal(407, res.statusCode);
assert('proxy-authenticate' in res.headers);
});
it('should send the "Proxy-Authorization" request header', async () => {
// set a proxy authentication function for this test
let gotAuth = false;
proxy.authenticate = (req) => {
gotAuth = true;
// username:password is "foo:bar"
return (
req.headers['proxy-authorization'] === 'Basic Zm9vOmJhcg=='
);
};
// set HTTP "request" event handler for this test
httpServer.once('request', (req, res) => {
res.end(JSON.stringify(req.headers));
});
const authProxy = new URL(proxyUrl.href);
authProxy.username = 'foo';
authProxy.password = 'bar';
const agent = new HttpProxyAgent(authProxy);
const res = await req(httpServerUrl, { agent });
const body = await json(res);
expect(gotAuth).toEqual(true);
expect(body.host).toEqual(httpServerUrl.host);
expect(body).toHaveProperty('via');
});
it('should emit an "error" event on the `http.ClientRequest` if the proxy does not exist', async () => {
// port 4 is a reserved, but "unassigned" port
const agent = new HttpProxyAgent('http://127.0.0.1:4');
let err: NodeJS.ErrnoException | undefined;
try {
await req('http://example.com', { agent });
} catch (_err) {
err = _err as NodeJS.ErrnoException;
}
assert(err);
expect(err.code).toEqual('ECONNREFUSED');
});
it('should allow custom proxy "headers" object', async () => {
httpServer.once('request', (req, res) => {
res.end(JSON.stringify(req.headers));
});
const agent = new HttpProxyAgent(proxyUrl, {
headers: { Foo: 'bar' },
});
const res = await req(httpServerUrl, { agent });
const body = await json(res);
expect(body.foo).toEqual('bar');
});
it('should allow custom proxy "headers" function', async () => {
let count = 1;
httpServer.on('request', (req, res) => {
res.end(JSON.stringify(req.headers));
});
const agent = new HttpProxyAgent(proxyUrl, {
headers: () => ({ number: count++ }),
});
const res = await req(httpServerUrl, { agent });
const body = await json(res);
expect(body.number).toEqual('1');
const res2 = await req(httpServerUrl, { agent });
const body2 = await json(res2);
expect(body2.number).toEqual('2');
});
it('should not send a port number for the default port', async () => {
httpServer.once('request', (req, res) => {
res.end(JSON.stringify(req.headers));
});
const agent = new HttpProxyAgent(proxyUrl);
agent.defaultPort = +httpServerUrl.port;
const res = await req(httpServerUrl, { agent });
const body = await json(res);
expect(body.host).toEqual(httpServerUrl.hostname);
});
it('should work with `keepAlive: true`', async () => {
httpServer.on('request', (req, res) => {
res.end(JSON.stringify(req.headers));
});
const agent = new HttpProxyAgent(proxyUrl, { keepAlive: true });
try {
const res = await req(httpServerUrl, { agent });
expect(res.headers.connection).toEqual('keep-alive');
expect(res.statusCode).toEqual(200);
res.resume();
const s1 = res.socket;
await once(s1, 'free');
const res2 = await req(httpServerUrl, { agent });
expect(res2.headers.connection).toEqual('keep-alive');
expect(res2.statusCode).toEqual(200);
res2.resume();
const s2 = res2.socket;
assert(s1 === s2);
await once(s2, 'free');
} finally {
agent.destroy();
}
});
});
});