1'use strict';
2
3const common = require('../common');
4const http = require('http');
5const assert = require('assert');
6
7// When the response is ended immediately, `req` should emit `close`
8// after `res`
9{
10  const server = http.Server(common.mustCall((req, res) => {
11    let resClosed = false;
12    let reqClosed = false;
13
14    res.end();
15    let resFinished = false;
16    res.on('finish', common.mustCall(() => {
17      resFinished = true;
18      assert.strictEqual(resClosed, false);
19      assert.strictEqual(res.destroyed, false);
20      assert.strictEqual(resClosed, false);
21    }));
22    assert.strictEqual(req.destroyed, false);
23    res.on('close', common.mustCall(() => {
24      resClosed = true;
25      assert.strictEqual(resFinished, true);
26      assert.strictEqual(reqClosed, false);
27      assert.strictEqual(res.destroyed, true);
28    }));
29    assert.strictEqual(req.destroyed, false);
30    req.on('end', common.mustCall(() => {
31      assert.strictEqual(req.destroyed, false);
32    }));
33    req.on('close', common.mustCall(() => {
34      reqClosed = true;
35      assert.strictEqual(resClosed, true);
36      assert.strictEqual(req.destroyed, true);
37      assert.strictEqual(req._readableState.ended, true);
38    }));
39    res.socket.on('close', () => server.close());
40  }));
41
42  server.listen(0, common.mustCall(() => {
43    http.get({ port: server.address().port }, common.mustCall());
44  }));
45}
46
47// When there's no `data` handler attached to `req`,
48// `req` should emit `close` after `res`.
49{
50  const server = http.Server(common.mustCall((req, res) => {
51    let resClosed = false;
52    let reqClosed = false;
53
54    // This time, don't end the response immediately
55    setTimeout(() => res.end(), 100);
56    let resFinished = false;
57    res.on('finish', common.mustCall(() => {
58      resFinished = true;
59      assert.strictEqual(resClosed, false);
60      assert.strictEqual(res.destroyed, false);
61      assert.strictEqual(resClosed, false);
62    }));
63    assert.strictEqual(req.destroyed, false);
64    res.on('close', common.mustCall(() => {
65      resClosed = true;
66      assert.strictEqual(resFinished, true);
67      assert.strictEqual(reqClosed, false);
68      assert.strictEqual(res.destroyed, true);
69    }));
70    assert.strictEqual(req.destroyed, false);
71    req.on('end', common.mustCall(() => {
72      assert.strictEqual(req.destroyed, false);
73    }));
74    req.on('close', common.mustCall(() => {
75      reqClosed = true;
76      assert.strictEqual(resClosed, true);
77      assert.strictEqual(req.destroyed, true);
78      assert.strictEqual(req._readableState.ended, true);
79    }));
80    res.socket.on('close', () => server.close());
81  }));
82
83  server.listen(0, common.mustCall(() => {
84    http.get({ port: server.address().port }, common.mustCall());
85  }));
86}
87
88// When a `data` handler is `attached` to `req`
89// (i.e. the server is consuming  data from it), `req` should emit `close`
90// before `res`.
91// https://github.com/nodejs/node/pull/33035 introduced this change in behavior.
92// See https://github.com/nodejs/node/pull/33035#issuecomment-751482764
93{
94  const server = http.Server(common.mustCall((req, res) => {
95    let resClosed = false;
96    let reqClosed = false;
97
98    // Don't end the response immediately
99    setTimeout(() => res.end(), 100);
100    let resFinished = false;
101    req.on('data', () => {});
102    res.on('finish', common.mustCall(() => {
103      resFinished = true;
104      assert.strictEqual(resClosed, false);
105      assert.strictEqual(res.destroyed, false);
106      assert.strictEqual(resClosed, false);
107    }));
108    assert.strictEqual(req.destroyed, false);
109    res.on('close', common.mustCall(() => {
110      resClosed = true;
111      assert.strictEqual(resFinished, true);
112      assert.strictEqual(reqClosed, true);
113      assert.strictEqual(res.destroyed, true);
114    }));
115    assert.strictEqual(req.destroyed, false);
116    req.on('end', common.mustCall(() => {
117      assert.strictEqual(req.destroyed, false);
118    }));
119    req.on('close', common.mustCall(() => {
120      reqClosed = true;
121      assert.strictEqual(resClosed, false);
122      assert.strictEqual(req.destroyed, true);
123      assert.strictEqual(req._readableState.ended, true);
124    }));
125    res.socket.on('close', () => server.close());
126  }));
127
128  server.listen(0, common.mustCall(() => {
129    http.get({ port: server.address().port }, common.mustCall());
130  }));
131}
132