mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
test: add http server consumed timeout
This commit is contained in:
@@ -2292,6 +2292,9 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
|
||||
|
||||
flags: NewFlags(debug_mode) = .{},
|
||||
|
||||
/// timeout in seconds set via IncomingMessage.setTimeout().
|
||||
request_timeout_seconds: u8 = 0,
|
||||
|
||||
upgrade_context: ?*uws.uws_socket_context_t = null,
|
||||
|
||||
/// We can only safely free once the request body promise is finalized
|
||||
@@ -4477,6 +4480,10 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
|
||||
|
||||
assert(this.resp == resp);
|
||||
|
||||
if (this.request_timeout_seconds > 0) {
|
||||
resp.timeout(this.request_timeout_seconds);
|
||||
}
|
||||
|
||||
this.flags.is_waiting_for_request_body = last == false;
|
||||
if (this.isAbortedOrEnded() or this.flags.has_marked_complete) return;
|
||||
if (!last and chunk.len == 0) {
|
||||
@@ -4647,8 +4654,10 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
|
||||
|
||||
pub fn setTimeout(this: *RequestContext, seconds: c_uint) bool {
|
||||
if (this.resp) |resp| {
|
||||
resp.timeout(@min(seconds, 255));
|
||||
if (seconds > 0) {
|
||||
const secs: u8 = @truncate(@min(seconds, 255));
|
||||
this.request_timeout_seconds = secs;
|
||||
resp.timeout(secs);
|
||||
if (secs > 0) {
|
||||
|
||||
// we only set the timeout callback if we wanna the timeout event to be triggered
|
||||
// the connection will be closed so the abort handler will be called after the timeout
|
||||
@@ -4659,6 +4668,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
|
||||
}
|
||||
} else {
|
||||
// if the timeout is 0, we don't need to trigger the timeout event
|
||||
this.request_timeout_seconds = 0;
|
||||
resp.clearTimeout();
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const http = require('http');
|
||||
|
||||
const durationBetweenIntervals = [];
|
||||
let timeoutTooShort = false;
|
||||
const TIMEOUT = common.platformTimeout(200);
|
||||
const INTERVAL = Math.floor(TIMEOUT / 8);
|
||||
|
||||
runTest(TIMEOUT);
|
||||
|
||||
function runTest(timeoutDuration) {
|
||||
let intervalWasInvoked = false;
|
||||
let newTimeoutDuration = 0;
|
||||
const closeCallback = (err) => {
|
||||
assert.ifError(err);
|
||||
if (newTimeoutDuration) {
|
||||
runTest(newTimeoutDuration);
|
||||
}
|
||||
};
|
||||
|
||||
const server = http.createServer((req, res) => {
|
||||
server.close(common.mustCall(closeCallback));
|
||||
|
||||
res.writeHead(200);
|
||||
res.flushHeaders();
|
||||
|
||||
req.setTimeout(timeoutDuration, () => {
|
||||
if (!intervalWasInvoked) {
|
||||
// Interval wasn't invoked, probably because the machine is busy with
|
||||
// other things. Try again with a longer timeout.
|
||||
newTimeoutDuration = timeoutDuration * 2;
|
||||
console.error('The interval was not invoked.');
|
||||
console.error(`Trying w/ timeout of ${newTimeoutDuration}.`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (timeoutTooShort) {
|
||||
intervalWasInvoked = false;
|
||||
timeoutTooShort = false;
|
||||
newTimeoutDuration =
|
||||
Math.max(...durationBetweenIntervals, timeoutDuration) * 2;
|
||||
console.error(`Time between intervals: ${durationBetweenIntervals}`);
|
||||
console.error(`Trying w/ timeout of ${newTimeoutDuration}`);
|
||||
return;
|
||||
}
|
||||
|
||||
assert.fail('Request timeout should not fire');
|
||||
});
|
||||
|
||||
req.resume();
|
||||
req.once('end', () => {
|
||||
res.end();
|
||||
});
|
||||
});
|
||||
|
||||
server.listen(0, common.mustCall(() => {
|
||||
const req = http.request({
|
||||
port: server.address().port,
|
||||
method: 'POST'
|
||||
}, () => {
|
||||
let lastIntervalTimestamp = Date.now();
|
||||
const interval = setInterval(() => {
|
||||
const lastDuration = Date.now() - lastIntervalTimestamp;
|
||||
durationBetweenIntervals.push(lastDuration);
|
||||
lastIntervalTimestamp = Date.now();
|
||||
if (lastDuration > timeoutDuration / 2) {
|
||||
// The interval is supposed to be about 1/8 of the timeout duration.
|
||||
// If it's running so infrequently that it's greater than 1/2 the
|
||||
// timeout duration, then run the test again with a longer timeout.
|
||||
timeoutTooShort = true;
|
||||
}
|
||||
intervalWasInvoked = true;
|
||||
req.write('a');
|
||||
}, INTERVAL);
|
||||
setTimeout(() => {
|
||||
clearInterval(interval);
|
||||
req.end();
|
||||
}, timeoutDuration);
|
||||
});
|
||||
req.write('.');
|
||||
}));
|
||||
}
|
||||
Reference in New Issue
Block a user