const https = require('https');
const fs = require('fs');
const path = require('path');
// Note: In a real application, you would use proper SSL certificates
// For demonstration, we'll use a self-signed certificate and disable strict SSL verification
// Create a custom HTTPS agent with SSL/TLS configuration
const customHttpsAgent = new https.Agent({
// Keep connections alive
keepAlive: true,
// Maximum number of sockets to allow per host
maxSockets: 10,
// Maximum time to keep sockets open when idle (ms)
keepAliveMsecs: 10000,
// Maximum number of sockets to leave open in a free state
maxFreeSockets: 10,
// SSL/TLS options
rejectUnauthorized: false, // WARNING: Only for testing with self-signed certs
// In a production environment, you would specify proper certificate authorities
// ca: fs.readFileSync('path/to/ca-cert.pem'),
// For client certificate authentication (mutual TLS)
// cert: fs.readFileSync('path/to/client-cert.pem'),
// key: fs.readFileSync('path/to/client-key.pem'),
// Minimum TLS version
minVersion: 'TLSv1.2',
// Cipher suites (example of secure configuration)
ciphers: [
'TLS_AES_256_GCM_SHA384',
'TLS_CHACHA20_POLY1305_SHA256',
'TLS_AES_128_GCM_SHA256',
'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384',
'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384',
'TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256',
'TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256',
'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256',
'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256'
].join(':'),
// Honor server's cipher suite order
honorCipherOrder: true,
// Enable OCSP stapling
requestCert: true,
// Timeout for the TLS handshake
handshakeTimeout: 10000
});
// Make a secure request using the custom agent
console.log('Making HTTPS request with custom agent...');
// Note: Using a test API that supports HTTPS
const options = {
hostname: 'jsonplaceholder.typicode.com',
path: '/todos/1',
method: 'GET',
agent: customHttpsAgent,
headers: {
'User-Agent': 'Node.js HTTPS Agent Demo',
'Accept': 'application/json'
}
};
const req = https.request(options, (res) => {
console.log(`\nResponse status: ${res.statusCode} ${res.statusMessage}`);
console.log('Response headers:', JSON.stringify(res.headers, null, 2));
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('\nResponse body:');
console.log(JSON.stringify(JSON.parse(data), null, 2));
// Log agent stats
console.log('\nAgent stats after request:');
console.log('Free sockets:', Object.keys(customHttpsAgent.freeSockets).length);
console.log('Active sockets:', Object.keys(customHttpsAgent.sockets).length);
// Make another request to demonstrate connection reuse
console.log('\nMaking another request to demonstrate connection reuse...');
makeAnotherRequest();
});
});
// Handle request errors
req.on('error', (err) => {
console.error('Request error:', err);
customHttpsAgent.destroy();
});
// End the request
req.end();
function makeAnotherRequest() {
const req2 = https.request({
hostname: 'jsonplaceholder.typicode.com',
path: '/todos/2',
method: 'GET',
agent: customHttpsAgent // Reusing the same agent
}, (res) => {
console.log(`\nSecond response status: ${res.statusCode}`);
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('Second response body:', JSON.parse(data).title);
// Final agent stats
console.log('\nFinal agent stats:');
console.log('Free sockets:', Object.keys(customHttpsAgent.freeSockets).length);
console.log('Active sockets:', Object.keys(customHttpsAgent.sockets).length);
// Destroy the agent when done
customHttpsAgent.destroy();
console.log('\nAgent destroyed');
});
});
req2.on('error', (err) => {
console.error('Second request error:', err);
customHttpsAgent.destroy();
});
req2.end();
}