const http = require('http');
const https = require('https');
const { URL } = require('url');
// Configuration
const CONFIG = {
// Test server settings
testServer: {
port: 3008,
// Delays for testing different timeout scenarios (in ms)
responseDelays: {
fast: 1000, // 1s - should complete successfully
slow: 5000, // 5s - should trigger timeout
verySlow: 10000 // 10s - should be aborted
}
},
// Timeout settings (in ms)
timeouts: {
connection: 2000, // Time to establish connection
request: 3000, // Time for the entire request
socket: 1000 // Time of inactivity on the socket
},
// Target URL for external request test
externalTestUrl: 'http://httpbin.org/delay/3' // 3 second delay
};
// Create a test server with configurable response delay
function createTestServer() {
const server = http.createServer((req, res) => {
const url = new URL(req.url, `http://${req.headers.host}`);
const delayType = url.searchParams.get('delay') || 'fast';
const delay = CONFIG.testServer.responseDelays[delayType] || 0;
console.log(`\n[${new Date().toISOString()}] Request received. Delay: ${delay}ms`);
// Set a timeout to simulate a slow response
setTimeout(() => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
status: 'success',
message: 'Response after delay',
delay: delay,
timestamp: new Date().toISOString()
}));
console.log(`[${new Date().toISOString()}] Response sent after ${delay}ms`);
}, delay);
});
return server;
}
// Function to make a request with timeouts
function makeRequest(url, options = {}) {
const { protocol } = new URL(url);
const client = protocol === 'https:' ? https : http;
// Set default timeout options
const timeoutOptions = {
timeout: CONFIG.timeouts.request,
...options
};
console.log(`\n=== Making request to ${url} ===`);
console.log('Timeout settings:', {
request: timeoutOptions.timeout,
connection: timeoutOptions.timeout,
socket: CONFIG.timeouts.socket
});
const startTime = Date.now();
const req = client.get(url, timeoutOptions, (res) => {
console.log(`\n[${new Date().toISOString()}] Response received`);
console.log(`Status: ${res.statusCode} ${res.statusMessage}`);
console.log('Headers:', JSON.stringify(res.headers, null, 2));
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
const endTime = Date.now();
const duration = endTime - startTime;
try {
const jsonData = JSON.parse(data);
console.log('Response body:', JSON.stringify(jsonData, null, 2));
} catch (e) {
console.log('Response body:', data);
}
console.log(`Request completed in ${duration}ms`);
});
});
// Set socket timeout (time of inactivity)
req.setTimeout(CONFIG.timeouts.socket, () => {
console.error(`\n[${new Date().toISOString()}] Socket timeout after ${CONFIG.timeouts.socket}ms of inactivity`);
req.abort(); // Abort the request
});
// Handle request timeout (entire request)
req.on('timeout', () => {
console.error(`\n[${new Date().toISOString()}] Request timeout after ${timeoutOptions.timeout}ms`);
req.abort();
});
// Handle errors
req.on('error', (err) => {
const endTime = Date.now();
console.error(`\n[${new Date().toISOString()}] Request error after ${endTime - startTime}ms:`,
err.code || err.message);
});
// Handle abort
req.on('abort', () => {
console.error(`[${new Date().toISOString()}] Request aborted`);
});
// Handle socket events
req.on('socket', (socket) => {
console.log(`[${new Date().toISOString()}] Socket assigned`);
socket.setTimeout(CONFIG.timeouts.connection, () => {
console.error(`[${new Date().toISOString()}] Connection timeout after ${CONFIG.timeouts.connection}ms`);
req.abort();
});
socket.on('connect', () => {
console.log(`[${new Date().toISOString()}] Socket connected`);
});
socket.on('error', (err) => {
console.error(`[${new Date().toISOString()}] Socket error:`, err.message);
});
});
return req;
}
// Main function to run the demo
async function runDemo() {
// Start the test server
const server = createTestServer();
server.listen(CONFIG.testServer.port, () => {
console.log(`Test server running at http://localhost:${CONFIG.testServer.port}`);
console.log('Available test endpoints:');
console.log(`- Fast response: http://localhost:${CONFIG.testServer.port}/?delay=fast`);
console.log(`- Slow response: http://localhost:${CONFIG.testServer.port}/?delay=slow`);
console.log(`- Very slow response: http://localhost:${CONFIG.testServer.port}/?delay=verySlow`);
console.log('\n=== Starting timeout demo ===\n');
// Run test cases with different timeouts
const testCases = [
{
name: 'Fast response (should succeed)',
url: `http://localhost:${CONFIG.testServer.port}/?delay=fast`,
options: { timeout: 5000 }
},
{
name: 'Slow response (should timeout)',
url: `http://localhost:${CONFIG.testServer.port}/?delay=slow`,
options: { timeout: 3000 }
},
{
name: 'External request with timeout',
url: CONFIG.externalTestUrl,
options: { timeout: 2000 },
skip: false // Set to true to skip external requests
}
];
// Run test cases sequentially
(async function runTests(index = 0) {
if (index >= testCases.length) {
console.log('\n=== All tests completed ===');
console.log('The test server is still running. Press Ctrl+C to stop it.');
console.log(`Visit http://localhost:${CONFIG.testServer.port} in your browser for more testing.`);
return;
}
const test = testCases[index];
if (test.skip) {
console.log(`\n=== Skipping: ${test.name} ===`);
runTests(index + 1);
return;
}
console.log(`\n=== Test ${index + 1}: ${test.name} ===`);
console.log(`URL: ${test.url}`);
await new Promise((resolve) => {
const req = makeRequest(test.url, test.options);
req.on('close', () => {
// Add a small delay between tests
setTimeout(resolve, 2000);
});
});
// Run next test
runTests(index + 1);
})();
});
// Handle server errors
server.on('error', (err) => {
console.error('Server error:', err);
});
// Handle process termination
process.on('SIGINT', () => {
console.log('\nShutting down server...');
server.close(() => {
console.log('Server closed');
process.exit(0);
});
});
}
// Run the demo
runDemo().catch(console.error);