'use strict'; const common = require('../common'); // Here we are testing the HTTP server module's flood prevention mechanism. // When writeable.write returns false (ie the underlying send() indicated the // native buffer is full), the HTTP server cork()s the readable part of the // stream. This means that new requests will not be read (however request which // have already been read, but are awaiting processing will still be // processed). // Normally when the writable stream emits a 'drain' event, the server then // uncorks the readable stream, although we aren't testing that part here. // The issue being tested exists in Node.js 0.10.20 and is resolved in 0.10.21 // and newer. switch (process.argv[2]) { case undefined: return parent(); case 'child': return child(); default: throw new Error(`Unexpected value: ${process.argv[2]}`); } function parent() { const http = require('http'); const bigResponse = Buffer.alloc(10240, 'x'); let backloggedReqs = 0; const server = http.createServer(function(req, res) { res.setHeader('content-length', bigResponse.length); if (!res.write(bigResponse)) { if (backloggedReqs === 0) { // Once the native buffer fills (ie write() returns false), the flood // prevention should kick in. // This means the stream should emit no more 'data' events. However we // may still be asked to process more requests if they were read before // the flood-prevention mechanism activated. setImmediate(() => { req.socket.on('data', common.mustNotCall('Unexpected data received')); }); } backloggedReqs++; } res.end(); }); server.on('connection', common.mustCall()); server.listen(0, function() { const spawn = require('child_process').spawn; const args = [__filename, 'child', this.address().port]; const child = spawn(process.execPath, args, { stdio: 'inherit' }); child.on('close', common.mustCall(function() { server.close(); })); server.setTimeout(200, common.mustCallAtLeast(function() { child.kill(); }, 1)); }); } function child() { const net = require('net'); const port = +process.argv[3]; const conn = net.connect({ port }); let req = `GET / HTTP/1.1\r\nHost: localhost:${port}\r\nAccept: */*\r\n\r\n`; req = req.repeat(10240); conn.on('connect', write); // `drain` should fire once and only once conn.on('drain', common.mustCall(write)); function write() { while (false !== conn.write(req, 'ascii')); } }