const http = require('http');
// Create a server to handle large uploads with flow control
const server = http.createServer((req, res) => {
if (req.method === 'POST' && req.url === '/large-upload') {
// Set up variables to track data
let dataSize = 0;
let chunks = 0;
// Switch to pause mode (by default it's in flowing mode)
req.pause();
console.log('Incoming large upload - using flow control');
// Process data in chunks
function processNextChunk() {
// Resume the stream to get more data
req.resume();
// Set a timeout to pause after a bit
setTimeout(() => {
// Pause the stream again
req.pause();
console.log(`Processed chunk ${++chunks}, total ${dataSize} bytes so far`);
// If there's more data to process, schedule the next chunk
// Otherwise, wait for 'end' event to finish
if (!req.complete) {
// Schedule next chunk processing
setTimeout(processNextChunk, 100);
}
}, 100); // Process for 100ms, then pause
}
// Listen for data events
req.on('data', (chunk) => {
dataSize += chunk.length;
});
// Handle request end
req.on('end', () => {
console.log(`Upload complete: ${dataSize} bytes received in ${chunks} chunks`);
// Send a response
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify({
success: true,
bytesReceived: dataSize,
chunks: chunks
}));
});
// Handle errors
req.on('error', (err) => {
console.error('Request error:', err);
res.writeHead(500, {'Content-Type': 'text/plain'});
res.end('Error processing upload: ' + err.message);
});
// Start processing
processNextChunk();
}
else {
// Handle other requests
res.writeHead(404, {'Content-Type': 'text/plain'});
res.end('Not Found');
}
});
// Start server
const PORT = 8080;
server.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}/`);
// Create a test client to simulate large upload
console.log('Simulating large upload...');
const req = http.request({
hostname: 'localhost',
port: PORT,
path: '/large-upload',
method: 'POST',
headers: {
'Content-Type': 'application/octet-stream'
}
}, (res) => {
// Handle response
let responseData = '';
res.on('data', (chunk) => {
responseData += chunk;
});
res.on('end', () => {
console.log('Server response:', responseData);
// Close the server after the test
server.close();
});
});
req.on('error', (err) => {
console.error('Upload request error:', err);
});
// Generate and send a large body in chunks
function sendChunk(i, total) {
if (i >= total) {
// All chunks sent, end the request
req.end();
return;
}
// Create a 10KB chunk
const chunk = Buffer.alloc(10240);
chunk.fill(65 + (i % 26)); // Fill with repeating letters
// Write the chunk
const canContinue = req.write(chunk);
// Log progress
if (i % 10 === 0) {
console.log(`Sent chunk ${i}/${total} (${i * 10240} bytes)`);
}
// If we can continue writing, schedule next chunk
if (canContinue) {
// Schedule next chunk
setImmediate(() => sendChunk(i + 1, total));
} else {
// If backpressure is applied, wait for drain event
console.log('Backpressure applied, waiting for drain');
req.once('drain', () => {
console.log('Drained, continuing upload');
sendChunk(i + 1, total);
});
}
}
// Start sending chunks (50 chunks = ~500KB)
sendChunk(0, 50);
});