Skip to content

Commit 6d0cebd

Browse files
committed
createClient url+tls invariant violation check
1 parent 2fc79bd commit 6d0cebd

File tree

2 files changed

+82
-16
lines changed

2 files changed

+82
-16
lines changed

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

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ describe('Client', () => {
5858
{
5959
socket: {
6060
host: 'localhost',
61-
port: 6379
61+
port: 6379,
62+
tls: false
6263
},
6364
username: 'user',
6465
password: 'secret',
@@ -103,12 +104,58 @@ describe('Client', () => {
103104
{
104105
socket: {
105106
host: 'localhost',
107+
tls: false
106108
}
107109
}
108110
);
109111
});
110112
});
111113

114+
describe('parseOptions', () => {
115+
it('should throw error if tls socket option is set to true and the url protocol is "redis:"', () => {
116+
assert.throws(
117+
() => RedisClient.parseOptions({
118+
url: 'redis://localhost',
119+
socket: {
120+
tls: true
121+
}
122+
}),
123+
TypeError
124+
);
125+
});
126+
it('should throw error if tls socket option is set to false and the url protocol is "rediss:"', () => {
127+
assert.throws(
128+
() => RedisClient.parseOptions({
129+
url: 'rediss://localhost',
130+
socket: {
131+
tls: false
132+
}
133+
}),
134+
TypeError
135+
);
136+
});
137+
it('should not throw when tls socket option and url protocol matches"', () => {
138+
assert.equal(
139+
RedisClient.parseOptions({
140+
url: 'rediss://localhost',
141+
socket: {
142+
tls: true
143+
}
144+
}).socket.tls,
145+
true
146+
);
147+
assert.equal(
148+
RedisClient.parseOptions({
149+
url: 'redis://localhost',
150+
socket: {
151+
tls: false
152+
}
153+
}).socket.tls,
154+
false
155+
);
156+
});
157+
});
158+
112159
describe('connect', () => {
113160
testUtils.testWithClient('connect should return the client instance', async client => {
114161
try {

packages/client/lib/client/index.ts

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -157,21 +157,45 @@ export default class RedisClient<
157157
return new (RedisClient.extend(options))(options);
158158
}
159159

160-
static parseURL(url: string): RedisClientOptions {
160+
static parseOptions<O extends RedisClientOptions>(options: O): O {
161+
if (options?.url) {
162+
const parsed = RedisClient.parseURL(options.url);
163+
if (options.socket) {
164+
if (options.socket.tls !== undefined && options.socket.tls !== parsed.socket.tls) {
165+
throw new TypeError(`tls socket option is set to ${options.socket.tls} which is mismatch with protocol or the URL ${options.url} passed`)
166+
}
167+
parsed.socket = Object.assign(options.socket, parsed.socket);
168+
}
169+
170+
Object.assign(options, parsed);
171+
}
172+
return options;
173+
}
174+
175+
static parseURL(url: string): RedisClientOptions & {
176+
socket: Exclude<RedisClientOptions['socket'], undefined> & {
177+
tls: boolean
178+
}
179+
} {
161180
// https://www.iana.org/assignments/uri-schemes/prov/redis
162181
const { hostname, port, protocol, username, password, pathname } = new URL(url),
163-
parsed: RedisClientOptions = {
182+
parsed: RedisClientOptions & {
183+
socket: Exclude<RedisClientOptions['socket'], undefined> & {
184+
tls: boolean
185+
}
186+
} = {
164187
socket: {
165-
host: hostname
188+
host: hostname,
189+
tls: false
166190
}
167191
};
168192

169-
if (protocol === 'rediss:') {
170-
(parsed.socket as RedisTlsSocketOptions).tls = true;
171-
} else if (protocol !== 'redis:') {
193+
if (protocol !== 'redis:' && protocol !== 'rediss:') {
172194
throw new TypeError('Invalid protocol');
173195
}
174196

197+
parsed.socket.tls = protocol === 'rediss:';
198+
175199
if (port) {
176200
(parsed.socket as TcpSocketConnectOpts).port = Number(port);
177201
}
@@ -239,19 +263,14 @@ export default class RedisClient<
239263
}
240264

241265
#initiateOptions(options?: RedisClientOptions<M, F, S>): RedisClientOptions<M, F, S> | undefined {
242-
if (options?.url) {
243-
const parsed = RedisClient.parseURL(options.url);
244-
if (options.socket) {
245-
parsed.socket = Object.assign(options.socket, parsed.socket);
246-
}
247-
248-
Object.assign(options, parsed);
249-
}
250-
251266
if (options?.database) {
252267
this.#selectedDB = options.database;
253268
}
254269

270+
if (options) {
271+
return RedisClient.parseOptions(options);
272+
}
273+
255274
return options;
256275
}
257276

0 commit comments

Comments
 (0)