1'use strict'; 2 3const http = require('http'); 4 5const fixed = 'C'.repeat(20 * 1024); 6const storedBytes = Object.create(null); 7const storedBuffer = Object.create(null); 8const storedUnicode = Object.create(null); 9 10const useDomains = process.env.NODE_USE_DOMAINS; 11 12// Set up one global domain. 13let domain; 14if (useDomains) { 15 domain = require('domain'); 16 const gdom = domain.create(); 17 gdom.on('error', (er) => { 18 console.error('Error on global domain', er); 19 throw er; 20 }); 21 gdom.enter(); 22} 23 24module.exports = http.createServer((req, res) => { 25 if (useDomains) { 26 const dom = domain.create(); 27 dom.add(req); 28 dom.add(res); 29 } 30 31 // URL format: /<type>/<length>/<chunks>/<responseBehavior>/chunkedEnc 32 const params = req.url.split('/'); 33 const command = params[1]; 34 let body = ''; 35 const arg = params[2]; 36 const n_chunks = parseInt(params[3], 10); 37 const resHow = params.length >= 5 ? params[4] : 'normal'; 38 const chunkedEnc = params.length >= 6 && params[5] === '0' ? false : true; 39 let status = 200; 40 41 let n, i; 42 if (command === 'bytes') { 43 n = ~~arg; 44 if (n <= 0) 45 throw new Error('bytes called with n <= 0'); 46 if (storedBytes[n] === undefined) { 47 storedBytes[n] = 'C'.repeat(n); 48 } 49 body = storedBytes[n]; 50 } else if (command === 'buffer') { 51 n = ~~arg; 52 if (n <= 0) 53 throw new Error('buffer called with n <= 0'); 54 if (storedBuffer[n] === undefined) { 55 storedBuffer[n] = Buffer.allocUnsafe(n); 56 for (i = 0; i < n; i++) { 57 storedBuffer[n][i] = 'C'.charCodeAt(0); 58 } 59 } 60 body = storedBuffer[n]; 61 } else if (command === 'unicode') { 62 n = ~~arg; 63 if (n <= 0) 64 throw new Error('unicode called with n <= 0'); 65 if (storedUnicode[n] === undefined) { 66 storedUnicode[n] = '\u263A'.repeat(n); 67 } 68 body = storedUnicode[n]; 69 } else if (command === 'quit') { 70 res.connection.server.close(); 71 body = 'quitting'; 72 } else if (command === 'fixed') { 73 body = fixed; 74 } else if (command === 'echo') { 75 switch (resHow) { 76 case 'setHeader': 77 res.statusCode = 200; 78 res.setHeader('Content-Type', 'text/plain'); 79 res.setHeader('Transfer-Encoding', 'chunked'); 80 break; 81 case 'setHeaderWH': 82 res.setHeader('Content-Type', 'text/plain'); 83 res.writeHead(200, { 'Transfer-Encoding': 'chunked' }); 84 break; 85 default: 86 res.writeHead(200, { 87 'Content-Type': 'text/plain', 88 'Transfer-Encoding': 'chunked' 89 }); 90 } 91 req.pipe(res); 92 return; 93 } else { 94 status = 404; 95 body = 'not found\n'; 96 } 97 98 // example: http://localhost:port/bytes/512/4 99 // sends a 512 byte body in 4 chunks of 128 bytes 100 const len = body.length; 101 switch (resHow) { 102 case 'setHeader': 103 res.statusCode = status; 104 res.setHeader('Content-Type', 'text/plain'); 105 if (chunkedEnc) 106 res.setHeader('Transfer-Encoding', 'chunked'); 107 else 108 res.setHeader('Content-Length', len.toString()); 109 break; 110 case 'setHeaderWH': 111 res.setHeader('Content-Type', 'text/plain'); 112 if (chunkedEnc) 113 res.writeHead(status, { 'Transfer-Encoding': 'chunked' }); 114 else 115 res.writeHead(status, { 'Content-Length': len.toString() }); 116 break; 117 default: 118 if (chunkedEnc) { 119 res.writeHead(status, { 120 'Content-Type': 'text/plain', 121 'Transfer-Encoding': 'chunked' 122 }); 123 } else { 124 res.writeHead(status, { 125 'Content-Type': 'text/plain', 126 'Content-Length': len.toString() 127 }); 128 } 129 } 130 // send body in chunks 131 if (n_chunks > 1) { 132 const step = Math.floor(len / n_chunks) || 1; 133 for (i = 0, n = (n_chunks - 1); i < n; ++i) 134 res.write(body.slice(i * step, i * step + step)); 135 res.end(body.slice((n_chunks - 1) * step)); 136 } else { 137 res.end(body); 138 } 139}); 140