Skip to content

Commit be230f2

Browse files
authored
fix(client): Support IPv6 literals in URL (#3176)
Fixes #3175.
1 parent e30ab2d commit be230f2

File tree

2 files changed

+110
-2
lines changed

2 files changed

+110
-2
lines changed

packages/client/lib/client/index.spec.ts

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,114 @@ describe('Client', () => {
178178
});
179179

180180
assert.equal(client?.options?.database, 5);
181-
})
181+
});
182+
183+
describe('should correctly parse IPv6 literals', () => {
184+
it('redis://[::1]:6379', () => {
185+
assert.deepEqual(
186+
RedisClient.parseURL('redis://[::1]:6379'),
187+
{
188+
socket: {
189+
host: '::1',
190+
port: 6379,
191+
tls: false
192+
}
193+
}
194+
);
195+
});
196+
197+
it('redis://[2001:db8::1]:6379', () => {
198+
assert.deepEqual(
199+
RedisClient.parseURL('redis://[2001:db8::1]:6379'),
200+
{
201+
socket: {
202+
host: '2001:db8::1',
203+
port: 6379,
204+
tls: false
205+
}
206+
}
207+
);
208+
});
209+
210+
it('rediss://[::1]:6379', () => {
211+
assert.deepEqual(
212+
RedisClient.parseURL('rediss://[::1]:6379'),
213+
{
214+
socket: {
215+
host: '::1',
216+
port: 6379,
217+
tls: true
218+
}
219+
}
220+
);
221+
});
222+
223+
it('redis://[::1]', () => {
224+
assert.deepEqual(
225+
RedisClient.parseURL('redis://[::1]'),
226+
{
227+
socket: {
228+
host: '::1',
229+
tls: false
230+
}
231+
}
232+
);
233+
});
234+
235+
it('redis://[::1]:6379/5', () => {
236+
assert.deepEqual(
237+
RedisClient.parseURL('redis://[::1]:6379/5'),
238+
{
239+
database: 5,
240+
socket: {
241+
host: '::1',
242+
port: 6379,
243+
tls: false,
244+
}
245+
}
246+
);
247+
});
248+
249+
it('redis://user:secret@[::1]:6379', async () => {
250+
const result = RedisClient.parseURL('redis://user:secret@[::1]:6379');
251+
const expected: RedisClientOptions = {
252+
socket: {
253+
host: '::1',
254+
port: 6379,
255+
tls: false
256+
},
257+
username: 'user',
258+
password: 'secret',
259+
credentialsProvider: {
260+
credentials: async () => ({
261+
password: 'secret',
262+
username: 'user'
263+
}),
264+
type: 'async-credentials-provider'
265+
}
266+
};
267+
268+
// Compare everything except the credentials function
269+
const { credentialsProvider: resultCredProvider, ...resultRest } = result;
270+
const { credentialsProvider: expectedCredProvider, ...expectedRest } = expected;
271+
272+
// Compare non-function properties
273+
assert.deepEqual(resultRest, expectedRest);
274+
assert.equal(resultCredProvider?.type, expectedCredProvider?.type);
275+
276+
if (result?.credentialsProvider?.type === 'async-credentials-provider' &&
277+
expected?.credentialsProvider?.type === 'async-credentials-provider') {
278+
279+
// Compare the actual output of the credentials functions
280+
const resultCreds = await result.credentialsProvider.credentials();
281+
const expectedCreds = await expected.credentialsProvider.credentials();
282+
assert.deepEqual(resultCreds, expectedCreds);
283+
284+
} else {
285+
assert.fail('Credentials provider type mismatch');
286+
}
287+
});
288+
});
182289
});
183290

184291
describe('parseOptions', () => {

packages/client/lib/client/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,8 @@ export default class RedisClient<
388388
}
389389
} = {
390390
socket: {
391-
host: hostname,
391+
// Use net.SocketAddress.parse() once supported.
392+
host: hostname.replace(/^\[([0-9a-f:]+)\]$/, '$1'),
392393
tls: false
393394
}
394395
};

0 commit comments

Comments
 (0)