• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2const common = require('../common');
3
4// Here we are testing the HTTP server module's flood prevention mechanism.
5// When writeable.write returns false (ie the underlying send() indicated the
6// native buffer is full), the HTTP server cork()s the readable part of the
7// stream. This means that new requests will not be read (however request which
8// have already been read, but are awaiting processing will still be
9// processed).
10
11// Normally when the writable stream emits a 'drain' event, the server then
12// uncorks the readable stream, although we aren't testing that part here.
13
14// The issue being tested exists in Node.js 0.10.20 and is resolved in 0.10.21
15// and newer.
16
17switch (process.argv[2]) {
18  case undefined:
19    return parent();
20  case 'child':
21    return child();
22  default:
23    throw new Error(`Unexpected value: ${process.argv[2]}`);
24}
25
26function parent() {
27  const http = require('http');
28  const bigResponse = Buffer.alloc(10240, 'x');
29  let backloggedReqs = 0;
30
31  const server = http.createServer(function(req, res) {
32    res.setHeader('content-length', bigResponse.length);
33    if (!res.write(bigResponse)) {
34      if (backloggedReqs === 0) {
35        // Once the native buffer fills (ie write() returns false), the flood
36        // prevention should kick in.
37        // This means the stream should emit no more 'data' events. However we
38        // may still be asked to process more requests if they were read before
39        // the flood-prevention mechanism activated.
40        setImmediate(() => {
41          req.socket.on('data', common.mustNotCall('Unexpected data received'));
42        });
43      }
44      backloggedReqs++;
45    }
46    res.end();
47  });
48
49  server.on('connection', common.mustCall());
50
51  server.listen(0, function() {
52    const spawn = require('child_process').spawn;
53    const args = [__filename, 'child', this.address().port];
54    const child = spawn(process.execPath, args, { stdio: 'inherit' });
55    child.on('close', common.mustCall(function() {
56      server.close();
57    }));
58
59    server.setTimeout(200, common.mustCallAtLeast(function() {
60      child.kill();
61    }, 1));
62  });
63}
64
65function child() {
66  const net = require('net');
67
68  const port = +process.argv[3];
69  const conn = net.connect({ port });
70
71  let req = `GET / HTTP/1.1\r\nHost: localhost:${port}\r\nAccept: */*\r\n\r\n`;
72
73  req = req.repeat(10240);
74
75  conn.on('connect', write);
76
77  // `drain` should fire once and only once
78  conn.on('drain', common.mustCall(write));
79
80  function write() {
81    while (false !== conn.write(req, 'ascii'));
82  }
83}
84