const http = require('http');
const zlib = require('zlib');
// Create an HTTP server with compression
const server = http.createServer((req, res) => {
// Get the Accept-Encoding header
const acceptEncoding = req.headers['accept-encoding'] || '';
// Create a sample response (large string)
const sampleData = `
This is a sample text that will be compressed.
It contains multiple lines to demonstrate compression effectiveness.
`.repeat(500);
// Function to send the response with appropriate headers
function sendResponse(data, encoding) {
// Set Content-Encoding header if compression is used
const headers = {
'Content-Type': 'text/plain',
'Vary': 'Accept-Encoding',
'X-Original-Size': Buffer.byteLength(sampleData, 'utf8').toString(),
'X-Compressed-Size': encoding ? Buffer.byteLength(data).toString() : 'N/A',
'X-Compression-Ratio': encoding
? ((1 - (Buffer.byteLength(data) / Buffer.byteLength(sampleData, 'utf8'))) * 100).toFixed(2) + '%'
: '0%',
'X-Compression-Method': encoding || 'none'
};
if (encoding) {
headers['Content-Encoding'] = encoding;
}
res.writeHead(200, headers);
res.end(data);
}
// Log compression info
console.log(`\nNew request from ${req.socket.remoteAddress}`);
console.log(`Accept-Encoding: ${acceptEncoding || 'none'}`);
// Check what encodings the client supports
if (/\bgzip\b/.test(acceptEncoding)) {
// Client supports gzip
console.log('Using gzip compression');
zlib.gzip(sampleData, (err, compressed) => {
if (err) {
console.error('Gzip compression failed:', err);
sendResponse(sampleData); // Fall back to uncompressed
} else {
sendResponse(compressed, 'gzip');
logCompressionInfo(sampleData, compressed, 'gzip');
}
});
}
else if (/\bdeflate\b/.test(acceptEncoding)) {
// Client supports deflate
console.log('Using deflate compression');
zlib.deflate(sampleData, (err, compressed) => {
if (err) {
console.error('Deflate compression failed:', err);
sendResponse(sampleData); // Fall back to uncompressed
} else {
sendResponse(compressed, 'deflate');
logCompressionInfo(sampleData, compressed, 'deflate');
}
});
}
else if (/\bbr\b/.test(acceptEncoding)) {
// Client supports Brotli (if Node.js version supports it)
if (typeof zlib.brotliCompress === 'function') {
console.log('Using Brotli compression');
zlib.brotliCompress(sampleData, (err, compressed) => {
if (err) {
console.error('Brotli compression failed:', err);
sendResponse(sampleData); // Fall back to uncompressed
} else {
sendResponse(compressed, 'br');
logCompressionInfo(sampleData, compressed, 'brotli');
}
});
} else {
console.log('Brotli not supported in this Node.js version');
sendResponse(sampleData); // Fall back to uncompressed
}
}
else {
// No compression supported by client
console.log('No compression used');
sendResponse(sampleData);
}
});
// Helper function to log compression information
function logCompressionInfo(original, compressed, method) {
const originalSize = Buffer.byteLength(original, 'utf8');
const compressedSize = Buffer.byteLength(compressed);
const ratio = (1 - (compressedSize / originalSize)) * 100;
console.log('Compression Results:');
console.log(`- Method: ${method}`);
console.log(`- Original size: ${originalSize} bytes`);
console.log(`- Compressed size: ${compressedSize} bytes`);
console.log(`- Compression ratio: ${ratio.toFixed(2)}%`);
console.log(`- Space saved: ${(originalSize - compressedSize).toLocaleString()} bytes`);
}
// Start the server
const PORT = 3005;
server.listen(PORT, () => {
console.log(`Compression server running at http://localhost:${PORT}/`);
// Test the server with different compression methods
testCompression('gzip');
testCompression('deflate');
// Only test brotli if supported
if (typeof zlib.brotliCompress === 'function') {
testCompression('br');
}
// Test with no compression
testCompression('none');
});
// Function to test different compression methods
function testCompression(encoding) {
const options = {
hostname: 'localhost',
port: 3005,
path: '/',
method: 'GET',
headers: {}
};
if (encoding !== 'none') {
options.headers['Accept-Encoding'] = encoding;
}
console.log(`\nTesting with ${encoding !== 'none' ? encoding : 'no'} compression...`);
const req = http.request(options, (res) => {
let data = [];
console.log(`\nResponse for ${encoding}:`);
console.log(`Status: ${res.statusCode} ${res.statusMessage}`);
console.log('Headers:', {
'content-encoding': res.headers['content-encoding'] || 'none',
'x-original-size': res.headers['x-original-size'],
'x-compressed-size': res.headers['x-compressed-size'],
'x-compression-ratio': res.headers['x-compression-ratio'],
'x-compression-method': res.headers['x-compression-method']
});
res.on('data', (chunk) => {
data.push(chunk);
});
res.on('end', () => {
const response = Buffer.concat(data);
console.log(`Response size: ${response.length} bytes`);
// For compressed responses, try to decompress to verify
if (res.headers['content-encoding']) {
const decompress = res.headers['content-encoding'] === 'gzip' ? zlib.gunzip :
res.headers['content-encoding'] === 'deflate' ? zlib.inflate :
res.headers['content-encoding'] === 'br' ? zlib.brotliDecompress : null;
if (decompress) {
decompress(response, (err, decompressed) => {
if (err) {
console.error(`Error decompressing ${res.headers['content-encoding']}:`, err);
} else {
console.log(`Successfully decompressed ${res.headers['content-encoding']} response`);
console.log(`Decompressed size: ${decompressed.length} bytes`);
console.log(`First 100 chars: ${decompressed.toString('utf8', 0, 100)}...`);
}
});
}
} else {
console.log(`First 100 chars: ${response.toString('utf8', 0, 100)}...`);
}
});
});
req.on('error', (err) => {
console.error(`Request error with ${encoding}:`, err);
});
req.end();
}
// Handle server errors
server.on('error', (err) => {
console.error('Server error:', err);
});
// Handle process termination
process.on('SIGINT', () => {
console.log('\nShutting down compression server...');
server.close(() => {
console.log('Server closed');
process.exit(0);
});
});