11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ciconst common = require('../common');
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ci// Here we are testing the HTTP server module's flood prevention mechanism.
51cb0ef41Sopenharmony_ci// When writeable.write returns false (ie the underlying send() indicated the
61cb0ef41Sopenharmony_ci// native buffer is full), the HTTP server cork()s the readable part of the
71cb0ef41Sopenharmony_ci// stream. This means that new requests will not be read (however request which
81cb0ef41Sopenharmony_ci// have already been read, but are awaiting processing will still be
91cb0ef41Sopenharmony_ci// processed).
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ci// Normally when the writable stream emits a 'drain' event, the server then
121cb0ef41Sopenharmony_ci// uncorks the readable stream, although we aren't testing that part here.
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ci// The issue being tested exists in Node.js 0.10.20 and is resolved in 0.10.21
151cb0ef41Sopenharmony_ci// and newer.
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ciswitch (process.argv[2]) {
181cb0ef41Sopenharmony_ci  case undefined:
191cb0ef41Sopenharmony_ci    return parent();
201cb0ef41Sopenharmony_ci  case 'child':
211cb0ef41Sopenharmony_ci    return child();
221cb0ef41Sopenharmony_ci  default:
231cb0ef41Sopenharmony_ci    throw new Error(`Unexpected value: ${process.argv[2]}`);
241cb0ef41Sopenharmony_ci}
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_cifunction parent() {
271cb0ef41Sopenharmony_ci  const http = require('http');
281cb0ef41Sopenharmony_ci  const bigResponse = Buffer.alloc(10240, 'x');
291cb0ef41Sopenharmony_ci  let backloggedReqs = 0;
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci  const server = http.createServer(function(req, res) {
321cb0ef41Sopenharmony_ci    res.setHeader('content-length', bigResponse.length);
331cb0ef41Sopenharmony_ci    if (!res.write(bigResponse)) {
341cb0ef41Sopenharmony_ci      if (backloggedReqs === 0) {
351cb0ef41Sopenharmony_ci        // Once the native buffer fills (ie write() returns false), the flood
361cb0ef41Sopenharmony_ci        // prevention should kick in.
371cb0ef41Sopenharmony_ci        // This means the stream should emit no more 'data' events. However we
381cb0ef41Sopenharmony_ci        // may still be asked to process more requests if they were read before
391cb0ef41Sopenharmony_ci        // the flood-prevention mechanism activated.
401cb0ef41Sopenharmony_ci        setImmediate(() => {
411cb0ef41Sopenharmony_ci          req.socket.on('data', common.mustNotCall('Unexpected data received'));
421cb0ef41Sopenharmony_ci        });
431cb0ef41Sopenharmony_ci      }
441cb0ef41Sopenharmony_ci      backloggedReqs++;
451cb0ef41Sopenharmony_ci    }
461cb0ef41Sopenharmony_ci    res.end();
471cb0ef41Sopenharmony_ci  });
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci  server.on('connection', common.mustCall());
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ci  server.listen(0, function() {
521cb0ef41Sopenharmony_ci    const spawn = require('child_process').spawn;
531cb0ef41Sopenharmony_ci    const args = [__filename, 'child', this.address().port];
541cb0ef41Sopenharmony_ci    const child = spawn(process.execPath, args, { stdio: 'inherit' });
551cb0ef41Sopenharmony_ci    child.on('close', common.mustCall(function() {
561cb0ef41Sopenharmony_ci      server.close();
571cb0ef41Sopenharmony_ci    }));
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci    server.setTimeout(200, common.mustCallAtLeast(function() {
601cb0ef41Sopenharmony_ci      child.kill();
611cb0ef41Sopenharmony_ci    }, 1));
621cb0ef41Sopenharmony_ci  });
631cb0ef41Sopenharmony_ci}
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_cifunction child() {
661cb0ef41Sopenharmony_ci  const net = require('net');
671cb0ef41Sopenharmony_ci
681cb0ef41Sopenharmony_ci  const port = +process.argv[3];
691cb0ef41Sopenharmony_ci  const conn = net.connect({ port });
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci  let req = `GET / HTTP/1.1\r\nHost: localhost:${port}\r\nAccept: */*\r\n\r\n`;
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci  req = req.repeat(10240);
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci  conn.on('connect', write);
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci  // `drain` should fire once and only once
781cb0ef41Sopenharmony_ci  conn.on('drain', common.mustCall(write));
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ci  function write() {
811cb0ef41Sopenharmony_ci    while (false !== conn.write(req, 'ascii'));
821cb0ef41Sopenharmony_ci  }
831cb0ef41Sopenharmony_ci}
84