1// Flags: --expose-internals 2'use strict'; 3const common = require('../common'); 4const assert = require('assert'); 5const http = require('http'); 6const net = require('net'); 7const MAX = +(process.argv[2] || 16 * 1024); // Command line option, or 16KB. 8 9const { getOptionValue } = require('internal/options'); 10 11console.log('pid is', process.pid); 12console.log('max header size is', getOptionValue('--max-http-header-size')); 13 14// Verify that we cannot receive more than 16KB of headers. 15 16function once(cb) { 17 let called = false; 18 return () => { 19 if (!called) { 20 called = true; 21 cb(); 22 } 23 }; 24} 25 26function finished(client, callback) { 27 ['abort', 'error', 'end'].forEach((e) => { 28 client.on(e, once(() => setImmediate(callback))); 29 }); 30} 31 32function fillHeaders(headers, currentSize, valid = false) { 33 // `llhttp` counts actual header name/value sizes, excluding the whitespace 34 // and stripped chars. 35 // OK, Content-Length, 0, X-CRASH, aaa... 36 headers += 'a'.repeat(MAX - currentSize); 37 38 // Generate valid headers 39 if (valid) { 40 headers = headers.slice(0, -1); 41 } 42 return headers + '\r\n\r\n'; 43} 44 45function writeHeaders(socket, headers) { 46 const array = []; 47 const chunkSize = 100; 48 let last = 0; 49 50 for (let i = 0; i < headers.length / chunkSize; i++) { 51 const current = (i + 1) * chunkSize; 52 array.push(headers.slice(last, current)); 53 last = current; 54 } 55 56 // Safety check we are chunking correctly 57 assert.strictEqual(array.join(''), headers); 58 59 next(); 60 61 function next() { 62 if (socket.destroyed) { 63 console.log('socket was destroyed early, data left to write:', 64 array.join('').length); 65 return; 66 } 67 68 const chunk = array.shift(); 69 70 if (chunk) { 71 console.log('writing chunk of size', chunk.length); 72 socket.write(chunk, next); 73 } else { 74 socket.end(); 75 } 76 } 77} 78 79function test1() { 80 console.log('test1'); 81 let headers = 82 'HTTP/1.1 200 OK\r\n' + 83 'Content-Length: 0\r\n' + 84 'X-CRASH: '; 85 86 // OK, Content-Length, 0, X-CRASH, aaa... 87 const currentSize = 2 + 14 + 1 + 7; 88 headers = fillHeaders(headers, currentSize); 89 90 const server = net.createServer((sock) => { 91 sock.once('data', () => { 92 writeHeaders(sock, headers); 93 sock.resume(); 94 }); 95 96 // The socket might error but that's ok 97 sock.on('error', () => {}); 98 }); 99 100 server.listen(0, common.mustCall(() => { 101 const port = server.address().port; 102 const client = http.get({ port: port }, common.mustNotCall()); 103 104 client.on('error', common.mustCall((err) => { 105 assert.strictEqual(err.code, 'HPE_HEADER_OVERFLOW'); 106 server.close(test2); 107 })); 108 })); 109} 110 111const test2 = common.mustCall(() => { 112 console.log('test2'); 113 let headers = 114 'GET / HTTP/1.1\r\n' + 115 'Host: localhost\r\n' + 116 'Agent: nod2\r\n' + 117 'X-CRASH: '; 118 119 // /, Host, localhost, Agent, node, X-CRASH, a... 120 const currentSize = 1 + 4 + 9 + 5 + 4 + 7; 121 headers = fillHeaders(headers, currentSize); 122 123 const server = http.createServer(common.mustNotCall()); 124 125 server.once('clientError', common.mustCall((err) => { 126 assert.strictEqual(err.code, 'HPE_HEADER_OVERFLOW'); 127 })); 128 129 server.listen(0, common.mustCall(() => { 130 const client = net.connect(server.address().port); 131 client.on('connect', () => { 132 writeHeaders(client, headers); 133 client.resume(); 134 }); 135 136 finished(client, common.mustCall(() => { 137 server.close(test3); 138 })); 139 })); 140}); 141 142const test3 = common.mustCall(() => { 143 console.log('test3'); 144 let headers = 145 'GET / HTTP/1.1\r\n' + 146 'Host: localhost\r\n' + 147 'Agent: nod3\r\n' + 148 'X-CRASH: '; 149 150 // /, Host, localhost, Agent, node, X-CRASH, a... 151 const currentSize = 1 + 4 + 9 + 5 + 4 + 7; 152 headers = fillHeaders(headers, currentSize, true); 153 154 console.log('writing', headers.length); 155 156 const server = http.createServer(common.mustCall((req, res) => { 157 res.end('hello from test3 server'); 158 server.close(); 159 })); 160 161 server.on('clientError', (err) => { 162 console.log(err.code); 163 if (err.code === 'HPE_HEADER_OVERFLOW') { 164 console.log(err.rawPacket.toString('hex')); 165 } 166 }); 167 server.on('clientError', common.mustNotCall()); 168 169 server.listen(0, common.mustCall(() => { 170 const client = net.connect(server.address().port); 171 client.on('connect', () => { 172 writeHeaders(client, headers); 173 client.resume(); 174 }); 175 176 client.pipe(process.stdout); 177 })); 178}); 179 180test1(); 181