Get your own Node server
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();
}

              
Making HTTPS request with custom agent...

Response status: 200 OK
Response headers: {
  "date": "Wed, 18 Jun 2025 06:44:01 GMT",
  "content-type": "application/json; charset=utf-8",
  "content-length": "83",
  "connection": "keep-alive",
  "x-powered-by": "Express",
  "x-ratelimit-limit": "1000",
  "x-ratelimit-remaining": "999",
  "x-ratelimit-reset": "1729154640",
  "vary": "Origin, Accept-Encoding",
  "access-control-allow-credentials": "true",
  "cache-control": "max-age=43200",
  "pragma": "no-cache",
  "expires": "-1",
  "x-content-type-options": "nosniff",
  "etag": "W/\"53-hEZ1i0xf3HEPhFJjxdUtzQjYFqo\"",
  "via": "1.1 vegur",
  "cf-cache-status": "HIT",
  "age": "0",
  "report-to": "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=...\"}],\"group\":\"cf-nel\",\"max_age\":604800}",
  "nel": "{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}",
  "server": "cloudflare",
  "cf-ray": "...-FRA",
  "alt-svc": "h3=\":443\"; ma=86400"
}

Response body:
{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}

Agent stats after request:
Free sockets: 1
Active sockets: 0

Making another request to demonstrate connection reuse...

Second response status: 200
Second response body: quis ut nam facilis et officia qui

Final agent stats:
Free sockets: 1
Active sockets: 0

Agent destroyed