Skip to content

Commit 968ae89

Browse files
committed
feat: applying maxIdleTimeout constraints for keep-alive and start timeout
[ci skip]
1 parent cea873b commit 968ae89

File tree

3 files changed

+132
-3
lines changed

3 files changed

+132
-3
lines changed

src/QUICConnection.ts

+19-3
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,12 @@ class QUICConnection extends EventTarget {
264264
},
265265
@context ctx: ContextTimed,
266266
): Promise<QUICConnection> {
267+
const timeoutTime = ctx.timer.getTimeout();
268+
if (timeoutTime !== Infinity && timeoutTime >= args.config.maxIdleTimeout) {
269+
throw new errors.ErrorQUICConnectionInvalidConfig(
270+
'connection timeout timer must be strictly less than maxIdleTimeout',
271+
);
272+
}
267273
ctx.signal.throwIfAborted();
268274
const abortProm = promise<never>();
269275
const abortHandler = () => {
@@ -292,7 +298,7 @@ class QUICConnection extends EventTarget {
292298
} finally {
293299
ctx.signal.removeEventListener('abort', abortHandler);
294300
}
295-
connection.logger.warn('secured');
301+
connection.logger.debug('secureEstablishedP');
296302
// After this is done
297303
// We need to establish the keep alive interval time
298304
if (connection.config.keepAliveIntervalTime != null) {
@@ -342,6 +348,16 @@ class QUICConnection extends EventTarget {
342348
}) {
343349
super();
344350
this.logger = logger ?? new Logger(`${this.constructor.name} ${scid}`);
351+
// Checking constraints
352+
if (
353+
config.keepAliveIntervalTime != null &&
354+
config.keepAliveIntervalTime >= config.maxIdleTimeout
355+
) {
356+
throw new errors.ErrorQUICConnectionInvalidConfig(
357+
'keepAliveIntervalTime must be shorter than maxIdleTimeout',
358+
);
359+
}
360+
345361
const quicheConfig = buildQuicheConfig(config);
346362
let conn: Connection;
347363
if (type === 'client') {
@@ -862,13 +878,13 @@ class QUICConnection extends EventTarget {
862878
);
863879
try {
864880
if (this.verifyCallback != null) this.verifyCallback(peerCertsPem);
865-
this.logger.warn('TLS verification succeeded');
881+
this.logger.debug('TLS verification succeeded');
866882
this.conn.sendAckEliciting();
867883
} catch (e) {
868884
// Force the connection to end.
869885
// Error 304 indicates cert chain failed verification.
870886
// Error 372 indicates cert chain was missing.
871-
this.logger.warn(
887+
this.logger.debug(
872888
`TLS fail due to [${e.message}], closing connection`,
873889
);
874890
this.conn.close(

src/errors.ts

+5
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ class ErrorQUICConnectionInternal<T> extends ErrorQUICConnection<T> {
112112
} & POJO;
113113
}
114114

115+
class ErrorQUICConnectionInvalidConfig<T> extends ErrorQUICConnection<T> {
116+
static description = 'QUIC connection invalid configuration';
117+
}
118+
115119
class ErrorQUICStream<T> extends ErrorQUIC<T> {
116120
static description = 'QUIC Stream error';
117121
}
@@ -163,6 +167,7 @@ export {
163167
ErrorQUICConnectionStartTimeOut,
164168
ErrorQUICConnectionIdleTimeOut,
165169
ErrorQUICConnectionInternal,
170+
ErrorQUICConnectionInvalidConfig,
166171
ErrorQUICStream,
167172
ErrorQUICStreamDestroyed,
168173
ErrorQUICStreamLocked,

tests/QUICClient.test.ts

+108
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,58 @@ describe(QUICClient.name, () => {
207207
}),
208208
).rejects.toThrow(errors.ErrorQUICConnectionStartTimeOut);
209209
});
210+
test('intervalTimeoutTime must be less than maxIdleTimeout', async () => {
211+
// Larger keepAliveIntervalTime throws
212+
await expect(
213+
QUICClient.createQUICClient({
214+
host: localhost,
215+
port: 56666 as Port,
216+
localHost: localhost,
217+
crypto: {
218+
ops: clientCrypto,
219+
},
220+
logger: logger.getChild(QUICClient.name),
221+
config: {
222+
maxIdleTimeout: 200,
223+
keepAliveIntervalTime: 1000,
224+
verifyPeer: false,
225+
},
226+
}),
227+
).rejects.toThrow(errors.ErrorQUICConnectionInvalidConfig);
228+
// Smaller keepAliveIntervalTime doesn't cause a problem
229+
await expect(
230+
QUICClient.createQUICClient({
231+
host: localhost,
232+
port: 56666 as Port,
233+
localHost: localhost,
234+
crypto: {
235+
ops: clientCrypto,
236+
},
237+
logger: logger.getChild(QUICClient.name),
238+
config: {
239+
maxIdleTimeout: 200,
240+
keepAliveIntervalTime: 100,
241+
verifyPeer: false,
242+
},
243+
}),
244+
).rejects.not.toThrow(errors.ErrorQUICConnectionInvalidConfig);
245+
// Not setting an interval doesn't cause a problem either
246+
await expect(
247+
QUICClient.createQUICClient({
248+
host: localhost,
249+
port: 56666 as Port,
250+
localHost: localhost,
251+
crypto: {
252+
ops: clientCrypto,
253+
},
254+
logger: logger.getChild(QUICClient.name),
255+
config: {
256+
maxIdleTimeout: 200,
257+
verifyPeer: false,
258+
},
259+
}),
260+
).rejects.not.toThrow(errors.ErrorQUICConnectionInvalidConfig);
261+
});
210262
test('client times out with ctx timer while starting', async () => {
211263
// QUICClient repeatedly dials until the connection timeout
212264
await expect(
@@ -229,6 +281,62 @@ describe(QUICClient.name, () => {
229281
),
230282
).rejects.toThrow(errors.ErrorQUICClientCreateTimeOut);
231283
});
284+
test('ctx timer must be less than maxIdleTimeout', async () => {
285+
// Larger timer throws
286+
await expect(
287+
QUICClient.createQUICClient(
288+
{
289+
host: localhost,
290+
port: 56666 as Port,
291+
localHost: localhost,
292+
crypto: {
293+
ops: clientCrypto,
294+
},
295+
logger: logger.getChild(QUICClient.name),
296+
config: {
297+
maxIdleTimeout: 200,
298+
verifyPeer: false,
299+
},
300+
},
301+
{ timer: new Timer({ delay: 1000 }) },
302+
),
303+
).rejects.toThrow(errors.ErrorQUICConnectionInvalidConfig);
304+
// Smaller keepAliveIntervalTime doesn't cause a problem
305+
await expect(
306+
QUICClient.createQUICClient(
307+
{
308+
host: localhost,
309+
port: 56666 as Port,
310+
localHost: localhost,
311+
crypto: {
312+
ops: clientCrypto,
313+
},
314+
logger: logger.getChild(QUICClient.name),
315+
config: {
316+
maxIdleTimeout: 200,
317+
verifyPeer: false,
318+
},
319+
},
320+
{ timer: new Timer({ delay: 100 }) },
321+
),
322+
).rejects.not.toThrow(errors.ErrorQUICConnectionInvalidConfig);
323+
// Not setting an interval doesn't cause a problem either
324+
await expect(
325+
QUICClient.createQUICClient({
326+
host: localhost,
327+
port: 56666 as Port,
328+
localHost: localhost,
329+
crypto: {
330+
ops: clientCrypto,
331+
},
332+
logger: logger.getChild(QUICClient.name),
333+
config: {
334+
maxIdleTimeout: 200,
335+
verifyPeer: false,
336+
},
337+
}),
338+
).rejects.not.toThrow(errors.ErrorQUICConnectionInvalidConfig);
339+
});
232340
test('client times out with ctx signal while starting', async () => {
233341
// QUICClient repeatedly dials until the connection timeout
234342
const abortController = new AbortController();

0 commit comments

Comments
 (0)