1// Copyright Joyent, Inc. and other Node contributors. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a 4// copy of this software and associated documentation files (the 5// "Software"), to deal in the Software without restriction, including 6// without limitation the rights to use, copy, modify, merge, publish, 7// distribute, sublicense, and/or sell copies of the Software, and to permit 8// persons to whom the Software is furnished to do so, subject to the 9// following conditions: 10// 11// The above copyright notice and this permission notice shall be included 12// in all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20// USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22'use strict'; 23const common = require('../common'); 24 25const assert = require('assert'); 26const http = require('http'); 27const net = require('net'); 28 29const tests = []; 30 31function test(fn) { 32 if (!tests.length) 33 process.nextTick(run); 34 tests.push(common.mustCall(fn)); 35} 36 37function run() { 38 const fn = tests.shift(); 39 if (fn) { 40 fn(run); 41 } 42} 43 44test(function serverTimeout(cb) { 45 const server = http.createServer(); 46 server.listen(common.mustCall(() => { 47 const s = server.setTimeout(50, common.mustCall((socket) => { 48 socket.destroy(); 49 server.close(); 50 cb(); 51 })); 52 assert.ok(s instanceof http.Server); 53 http.get({ 54 port: server.address().port 55 }).on('error', common.mustCall()); 56 })); 57}); 58 59test(function serverRequestTimeout(cb) { 60 const server = http.createServer(common.mustCall((req, res) => { 61 // Just do nothing, we should get a timeout event. 62 const s = req.setTimeout(50, common.mustCall((socket) => { 63 socket.destroy(); 64 server.close(); 65 cb(); 66 })); 67 assert.ok(s instanceof http.IncomingMessage); 68 })); 69 server.listen(common.mustCall(() => { 70 const req = http.request({ 71 port: server.address().port, 72 method: 'POST' 73 }); 74 req.on('error', common.mustCall()); 75 req.write('Hello'); 76 // req is in progress 77 })); 78}); 79 80test(function serverResponseTimeout(cb) { 81 const server = http.createServer(common.mustCall((req, res) => { 82 // Just do nothing, we should get a timeout event. 83 const s = res.setTimeout(50, common.mustCall((socket) => { 84 socket.destroy(); 85 server.close(); 86 cb(); 87 })); 88 assert.ok(s instanceof http.OutgoingMessage); 89 })); 90 server.listen(common.mustCall(() => { 91 http.get({ 92 port: server.address().port 93 }).on('error', common.mustCall()); 94 })); 95}); 96 97test(function serverRequestNotTimeoutAfterEnd(cb) { 98 const server = http.createServer(common.mustCall((req, res) => { 99 // Just do nothing, we should get a timeout event. 100 const s = req.setTimeout(50, common.mustNotCall()); 101 assert.ok(s instanceof http.IncomingMessage); 102 res.on('timeout', common.mustCall()); 103 })); 104 server.on('timeout', common.mustCall((socket) => { 105 socket.destroy(); 106 server.close(); 107 cb(); 108 })); 109 server.listen(common.mustCall(() => { 110 http.get({ 111 port: server.address().port 112 }).on('error', common.mustCall()); 113 })); 114}); 115 116test(function serverResponseTimeoutWithPipeline(cb) { 117 let caughtTimeout = ''; 118 let secReceived = false; 119 process.on('exit', () => { 120 assert.strictEqual(caughtTimeout, '/2'); 121 }); 122 const server = http.createServer((req, res) => { 123 if (req.url === '/2') 124 secReceived = true; 125 if (req.url === '/1') { 126 res.end(); 127 return; 128 } 129 const s = res.setTimeout(50, () => { 130 caughtTimeout += req.url; 131 }); 132 assert.ok(s instanceof http.OutgoingMessage); 133 }); 134 server.on('timeout', common.mustCall((socket) => { 135 if (secReceived) { 136 socket.destroy(); 137 server.close(); 138 cb(); 139 } 140 })); 141 server.listen(common.mustCall(() => { 142 const options = { 143 port: server.address().port, 144 allowHalfOpen: true, 145 }; 146 const c = net.connect(options, () => { 147 c.write('GET /1 HTTP/1.1\r\nHost: localhost\r\n\r\n'); 148 c.write('GET /2 HTTP/1.1\r\nHost: localhost\r\n\r\n'); 149 c.write('GET /3 HTTP/1.1\r\nHost: localhost\r\n\r\n'); 150 }); 151 })); 152}); 153 154test(function idleTimeout(cb) { 155 // Test that the an idle connection invokes the timeout callback. 156 const server = http.createServer(); 157 const s = server.setTimeout(50, common.mustCall((socket) => { 158 socket.destroy(); 159 server.close(); 160 cb(); 161 })); 162 assert.ok(s instanceof http.Server); 163 server.listen(common.mustCall(() => { 164 const options = { 165 port: server.address().port, 166 allowHalfOpen: true, 167 }; 168 const c = net.connect(options, () => { 169 // ECONNRESET could happen on a heavily-loaded server. 170 c.on('error', (e) => { 171 if (e.message !== 'read ECONNRESET') 172 throw e; 173 }); 174 c.write('GET /1 HTTP/1.1\r\nHost: localhost\r\n\r\n'); 175 // Keep-Alive 176 }); 177 })); 178}); 179 180test(function fastTimeout(cb) { 181 let connectionHandlerInvoked = false; 182 let timeoutHandlerInvoked = false; 183 let connectionSocket; 184 185 function invokeCallbackIfDone() { 186 if (connectionHandlerInvoked && timeoutHandlerInvoked) { 187 connectionSocket.destroy(); 188 server.close(); 189 cb(); 190 } 191 } 192 193 const server = http.createServer(common.mustCall((req, res) => { 194 req.on('timeout', common.mustNotCall()); 195 res.end(); 196 connectionHandlerInvoked = true; 197 invokeCallbackIfDone(); 198 })); 199 const s = server.setTimeout(1, common.mustCall((socket) => { 200 connectionSocket = socket; 201 timeoutHandlerInvoked = true; 202 invokeCallbackIfDone(); 203 })); 204 assert.ok(s instanceof http.Server); 205 server.listen(common.mustCall(() => { 206 const options = { 207 port: server.address().port, 208 allowHalfOpen: true, 209 }; 210 const c = net.connect(options, () => { 211 c.write('GET /1 HTTP/1.1\r\nHost: localhost\r\n\r\n'); 212 // Keep-Alive 213 }); 214 })); 215}); 216