1'use strict'; 2 3const common = require('../common'); 4const http = require('http'); 5const net = require('net'); 6const assert = require('assert'); 7 8// The maximum http chunk extension size is set in `src/node_http_parser.cc`. 9// These tests assert that once the extension size is reached, an HTTP 413 10// response is returned. 11// Currently, the max size is set to 16KiB (16384). 12 13// Verify that chunk extensions are limited in size when sent all together. 14{ 15 const server = http.createServer((req, res) => { 16 req.on('end', () => { 17 res.writeHead(200, { 'Content-Type': 'text/plain' }); 18 res.end('bye'); 19 }); 20 21 req.resume(); 22 }); 23 24 server.listen(0, () => { 25 const port = server.address().port; 26 const sock = net.connect(port); 27 let data = ''; 28 29 sock.on('data', (chunk) => data += chunk.toString('utf-8')); 30 31 sock.on('end', common.mustCall(function() { 32 assert.strictEqual(data, 'HTTP/1.1 413 Payload Too Large\r\nConnection: close\r\n\r\n'); 33 server.close(); 34 })); 35 36 sock.end('' + 37 'GET / HTTP/1.1\r\n' + 38 `Host: localhost:${port}\r\n` + 39 'Transfer-Encoding: chunked\r\n\r\n' + 40 '2;' + 'a'.repeat(17000) + '\r\n' + // Chunk size + chunk ext + CRLF 41 'AA\r\n' + // Chunk data 42 '0\r\n' + // Last chunk 43 '\r\n' // End of http message 44 ); 45 }); 46} 47 48// Verify that chunk extensions are limited in size when sent in parts 49{ 50 const server = http.createServer((req, res) => { 51 req.on('end', () => { 52 res.writeHead(200, { 'Content-Type': 'text/plain' }); 53 res.end('bye'); 54 }); 55 56 req.resume(); 57 }); 58 59 server.listen(0, () => { 60 const port = server.address().port; 61 const sock = net.connect(port); 62 let data = ''; 63 64 sock.on('data', (chunk) => data += chunk.toString('utf-8')); 65 66 sock.on('end', common.mustCall(function() { 67 assert.strictEqual(data, 'HTTP/1.1 413 Payload Too Large\r\nConnection: close\r\n\r\n'); 68 server.close(); 69 })); 70 71 sock.write('' + 72 'GET / HTTP/1.1\r\n' + 73 `Host: localhost:${port}\r\n` + 74 'Transfer-Encoding: chunked\r\n\r\n' + 75 '2;' // Chunk size + start of chunk-extension 76 ); 77 78 sock.write('A'.repeat(8500)); // Write half of the chunk-extension 79 80 queueMicrotask(() => { 81 sock.write('A'.repeat(8500) + '\r\n' + // Remaining half of the chunk-extension 82 'AA\r\n' + // Chunk data 83 '0\r\n' + // Last chunk 84 '\r\n' // End of http message 85 ); 86 }); 87 }); 88} 89 90// Verify the chunk extensions is correctly reset after a chunk 91{ 92 const server = http.createServer((req, res) => { 93 req.on('end', () => { 94 res.writeHead(200, { 'content-type': 'text/plain', 'connection': 'close', 'date': 'now' }); 95 res.end('bye'); 96 }); 97 98 req.resume(); 99 }); 100 101 server.listen(0, () => { 102 const port = server.address().port; 103 const sock = net.connect(port); 104 let data = ''; 105 106 sock.on('data', (chunk) => data += chunk.toString('utf-8')); 107 108 sock.on('end', common.mustCall(function() { 109 assert.strictEqual( 110 data, 111 'HTTP/1.1 200 OK\r\n' + 112 'content-type: text/plain\r\n' + 113 'connection: close\r\n' + 114 'date: now\r\n' + 115 'Transfer-Encoding: chunked\r\n' + 116 '\r\n' + 117 '3\r\n' + 118 'bye\r\n' + 119 '0\r\n' + 120 '\r\n', 121 ); 122 123 server.close(); 124 })); 125 126 sock.end('' + 127 'GET / HTTP/1.1\r\n' + 128 `Host: localhost:${port}\r\n` + 129 'Transfer-Encoding: chunked\r\n\r\n' + 130 '2;' + 'A'.repeat(10000) + '=bar\r\nAA\r\n' + 131 '2;' + 'A'.repeat(10000) + '=bar\r\nAA\r\n' + 132 '2;' + 'A'.repeat(10000) + '=bar\r\nAA\r\n' + 133 '0\r\n\r\n' 134 ); 135 }); 136} 137