@ -1,6 +1,6 @@
'use strict' ;
var common = require ( '../common' ) ;
var assert = require ( 'assert' ) ;
const common = require ( '../common' ) ;
const assert = require ( 'assert' ) ;
// Here we are testing the HTTP server module's flood prevention mechanism.
// When writeable.write returns false (ie the underlying send() indicated the
@ -18,29 +18,31 @@ switch (process.argv[2]) {
case 'child' :
return child ( ) ;
default :
throw new Error ( 'wtf' ) ;
throw new Error ( ` Unexpected value: ${ process . argv [ 2 ] } ` ) ;
}
function parent ( ) {
var http = require ( 'http' ) ;
var bigResponse = new Buffer ( 10240 ) . fill ( 'x' ) ;
const http = require ( 'http' ) ;
const bigResponse = new Buffer ( 10240 ) . fill ( 'x' ) ;
var gotTimeout = false ;
var childClosed = false ;
var requests = 0 ;
var connections = 0 ;
var backloggedReqs = 0 ;
var server = http . createServer ( function ( req , res ) {
const server = http . createServer ( function ( req , res ) {
requests ++ ;
res . setHeader ( 'content-length' , bigResponse . length ) ;
if ( ! res . write ( bigResponse ) ) {
if ( backloggedReqs == 0 ) {
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
// mechanism activated.
req . socket . on ( 'data' , function ( ) { assert ( false ) ; } ) ;
// the flood-prevention mechanism activated.
setImmediate ( ( ) => {
req . socket . on ( 'data' , ( ) => common . fail ( 'Unexpected data received' ) ) ;
} ) ;
}
backloggedReqs ++ ;
}
@ -51,38 +53,32 @@ function parent() {
connections ++ ;
} ) ;
server . setTimeout ( 200 , function ( conn ) {
gotTimeout = true ;
} ) ;
server . listen ( common . PORT , function ( ) {
var spawn = require ( 'child_process' ) . spawn ;
var args = [ __ filename , 'child' ] ;
var child = spawn ( process . execPath , args , { stdio : 'inherit' } ) ;
child . on ( 'close' , function ( code ) {
assert ( ! code ) ;
const spawn = require ( 'child_process' ) . spawn ;
const args = [ __ filename , 'child' ] ;
const child = spawn ( process . execPath , args , { stdio : 'inherit' } ) ;
child . on ( 'close' , function ( ) {
childClosed = true ;
server . close ( ) ;
} ) ;
server . setTimeout ( common . platformTimeout ( 200 ) , function ( conn ) {
gotTimeout = true ;
child . kill ( ) ;
} ) ;
} ) ;
process . on ( 'exit' , function ( ) {
assert ( gotTimeout ) ;
assert ( childClosed ) ;
assert . equal ( connections , 1 ) ;
// The number of requests we end up processing before the outgoing
// connection backs up and requires a drain is implementation-dependent.
console . log ( 'server got %d requests' , requests ) ;
console . log ( 'server sent %d backlogged requests' , backloggedReqs ) ;
console . log ( 'ok' ) ;
} ) ;
}
function child ( ) {
var net = require ( 'net' ) ;
const net = require ( 'net' ) ;
var conn = net . connect ( { port : common . PORT } ) ;
const conn = net . connect ( { port : common . PORT } ) ;
var req = 'GET / HTTP/1.1\r\nHost: localhost:' +
common . PORT + '\r\nAccept: */*\r\n\r\n' ;
@ -90,17 +86,13 @@ function child() {
req = new Array ( 10241 ) . join ( req ) ;
conn . on ( 'connect' , function ( ) {
//kill child after 1s of flooding
setTimeout ( function ( ) { conn . destroy ( ) ; } , 1000 ) ;
// Terminate child after flooding.
setTimeout ( function ( ) { conn . destroy ( ) ; } , common . platformTimeout ( 1000 ) ) ;
write ( ) ;
} ) ;
conn . on ( 'drain' , write ) ;
process . on ( 'exit' , function ( ) {
console . log ( 'ok - child' ) ;
} ) ;
function write ( ) {
while ( false !== conn . write ( req , 'ascii' ) ) ;
}