1'use strict';
2// Run this program with valgrind or efence with --expose_gc to expose the
3// problem.
4
5// Flags: --expose_gc
6
7require('../common');
8const assert = require('assert');
9const { HTTPParser } = require('_http_common');
10
11const kOnHeaders = HTTPParser.kOnHeaders | 0;
12const kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0;
13const kOnBody = HTTPParser.kOnBody | 0;
14const kOnMessageComplete = HTTPParser.kOnMessageComplete | 0;
15
16let headersComplete = 0;
17let messagesComplete = 0;
18
19function flushPool() {
20  Buffer.allocUnsafe(Buffer.poolSize - 1);
21  global.gc();
22}
23
24function demoBug(part1, part2) {
25  flushPool();
26
27  const parser = new HTTPParser();
28  parser.initialize(HTTPParser.REQUEST, {});
29
30  parser.headers = [];
31  parser.url = '';
32
33  parser[kOnHeaders] = function(headers, url) {
34    parser.headers = parser.headers.concat(headers);
35    parser.url += url;
36  };
37
38  parser[kOnHeadersComplete] = function(info) {
39    headersComplete++;
40    console.log('url', info.url);
41  };
42
43  parser[kOnBody] = () => {};
44
45  parser[kOnMessageComplete] = function() {
46    messagesComplete++;
47  };
48
49
50  // We use a function to eliminate references to the Buffer b
51  // We want b to be GCed. The parser will hold a bad reference to it.
52  (function() {
53    const b = Buffer.from(part1);
54    flushPool();
55
56    console.log('parse the first part of the message');
57    parser.execute(b, 0, b.length);
58  })();
59
60  flushPool();
61
62  (function() {
63    const b = Buffer.from(part2);
64
65    console.log('parse the second part of the message');
66    parser.execute(b, 0, b.length);
67    parser.finish();
68  })();
69
70  flushPool();
71}
72
73
74demoBug('POST /1', '/22 HTTP/1.1\r\n' +
75        'Content-Type: text/plain\r\n' +
76        'Content-Length: 4\r\n\r\n' +
77        'pong');
78
79demoBug('POST /1/22 HTTP/1.1\r\n' +
80        'Content-Type: tex', 't/plain\r\n' +
81        'Content-Length: 4\r\n\r\n' +
82        'pong');
83
84process.on('exit', function() {
85  assert.strictEqual(headersComplete, 2);
86  assert.strictEqual(messagesComplete, 2);
87  console.log('done!');
88});
89