Skip to content

Commit 5c00d48

Browse files
committed
adding redirect support
1 parent d4968ac commit 5c00d48

File tree

3 files changed

+66
-11
lines changed

3 files changed

+66
-11
lines changed

README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ const client = new HttpClient(options);
4141

4242
| option | default | type | required | details |
4343
|---------------------|--------------|------------|----------|--------------------------------------------------------------------------------------------------------------------------------------------|
44-
| abortController | `undefined` | `object` | no | See [abortController](#abortController) |
44+
| abortController | `undefined` | `object` | no | See [abortController](#abortController) |
4545
| connections | `50` | `number` | no | See [connections](#connections) |
46-
| fallback | `undefined` | `function` | no | Function to call when requests fail |
46+
| fallback | `undefined` | `function` | no | Function to call when requests fail, see [fallback](#fallback) |
47+
| followRedirects | `false` | `boolean` | no | Flag for whether to follow redirects or not, see [followRedirects](#followRedirects). |
4748
| keepAliveMaxTimeout | `undefined` | `number` | no | See [keepAliveMaxTimeout](#keepAliveMaxTimeout) |
4849
| keepAliveTimeout | `undefined` | `number` | no | See [keepAliveTimeout](#keepAliveTimeout) |
4950
| logger | `undefined ` | `object` | no | A logger which conform to a log4j interface |
@@ -72,6 +73,15 @@ Optional function to run when a request fails.
7273
// TBA
7374
```
7475

76+
##### followRedirects
77+
78+
TODO!!! decide what to do with the redirects stuff...
79+
80+
By default, the library does not follow redirect.
81+
If set to true it will follow redirects according to `maxRedirections`.
82+
It will by default throw on reaching `throwOnMaxRedirects`
83+
84+
7585
##### keepAliveMaxTimeout
7686

7787
Property is sent to the underlying http library.

lib/http-client.js

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Agent, request } from 'undici';
1+
import { Agent, request, interceptors } from 'undici';
22
import createError from 'http-errors';
33
import Opossum from 'opossum';
44
import abslog from 'abslog';
@@ -35,6 +35,7 @@ export default class HttpClient {
3535
autoRenewAbortController = false,
3636
connections = 50,
3737
fallback = undefined,
38+
followRedirects = false,
3839
keepAliveMaxTimeout = undefined,
3940
keepAliveTimeout = undefined,
4041
logger = undefined,
@@ -62,12 +63,19 @@ export default class HttpClient {
6263
timeout,
6364
});
6465

65-
this.#agent = new Agent({
66-
keepAliveMaxTimeout, // TODO unknown option, consider removing
67-
keepAliveTimeout, // TODO unknown option, consider removing
66+
const { redirect } = interceptors;
67+
let agent = new Agent({
68+
keepAliveMaxTimeout,
69+
keepAliveTimeout,
6870
connections,
69-
pipelining, // TODO unknown option, consider removing
71+
pipelining,
7072
});
73+
if (followRedirects) {
74+
agent = agent.compose(
75+
redirect({ maxRedirections: 1, throwOnMaxRedirects: true }),
76+
);
77+
}
78+
this.#agent = agent;
7179

7280
if (fallback) {
7381
this.#hasFallback = true;
@@ -77,11 +85,8 @@ export default class HttpClient {
7785

7886
async #request(options = {}) {
7987
const { statusCode, headers, trailers, body } = await request({
88+
dispatcher: this.#agent,
8089
...options,
81-
dispatcher: new Agent({
82-
keepAliveTimeout: 10,
83-
keepAliveMaxTimeout: 10,
84-
}),
8590
});
8691

8792
if (this.#throwOn400 && statusCode >= 400 && statusCode <= 499) {
@@ -157,6 +162,7 @@ export default class HttpClient {
157162
* Error class for the client
158163
*/
159164
export class HttpClientError extends Error {
165+
// Not sure if there is a need for this tbh, but I threw it in there so we can see how it feels.
160166
static ServerDown = 'EOPENBREAKER';
161167
constructor(message, { code, cause, options }) {
162168
super(message);

tests/http-client.test.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,45 @@ await test('http-client - abort controller', async (t) => {
155155
slowServer.close();
156156
});
157157

158+
await test('http-client - redirects', async (t) => {
159+
const to = http.createServer(async (request, response) => {
160+
response.writeHead(200);
161+
response.end();
162+
});
163+
to.listen(3033, host);
164+
165+
const from = http.createServer(async (request, response) => {
166+
if (request.url === '/redirect') {
167+
response.setHeader('location', 'http://localhost:3033');
168+
}
169+
response.writeHead(301);
170+
response.end();
171+
});
172+
from.listen(port, host);
173+
174+
await t.test('can follow redirects', async () => {
175+
const client = new HttpClient({ threshold: 50, followRedirects: true });
176+
const response = await client.request({
177+
method: 'GET',
178+
origin: `http://${host}:${port}`,
179+
path: '/redirect',
180+
});
181+
assert.strictEqual(response.statusCode, 200);
182+
});
183+
// await t.test.skip('throw on max redirects', async () => {});
184+
await t.test('does not follow redirects by default', async () => {
185+
const client = new HttpClient({ threshold: 50 });
186+
const response = await client.request({
187+
method: 'GET',
188+
origin: `http://${host}:${port}`,
189+
path: '/redirect',
190+
});
191+
assert.strictEqual(response.statusCode, 301);
192+
});
193+
from.close();
194+
to.close();
195+
});
196+
158197
await test('http-client - circuit breaker behaviour', async (t) => {
159198
const url = `http://${host}:${port}`;
160199
await t.test('opens on failure threshold', async () => {

0 commit comments

Comments
 (0)