// Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. var common = require('../common'); var assert = require('assert'); // Fix the memory explosion that happens when writing to a http request // where the server has destroyed the socket on us between a successful // first request, and a subsequent request that reuses the socket. // // This test should not be ported to v0.10 and higher, because the // problem is fixed by not ignoring ECONNRESET in the first place. var http = require('http'); var net = require('net'); var server = http.createServer(function(req, res) { // simulate a server that is in the process of crashing or something // it only crashes after the first request, but before the second, // which reuses the connection. res.end('hallo wereld\n', function() { setTimeout(function() { req.connection.destroy(); }, 100); }); }); var gotFirstResponse = false; var gotFirstData = false; var gotFirstEnd = false; server.listen(common.PORT, function() { var gotFirstResponse = false; var first = http.request({ port: common.PORT, path: '/' }); first.on('response', function(res) { gotFirstResponse = true; res.on('data', function(chunk) { gotFirstData = true; }); res.on('end', function() { gotFirstEnd = true; }) }); first.end(); second(); function second() { var sec = http.request({ port: common.PORT, path: '/', method: 'POST' }); var timer = setTimeout(write, 200); var writes = 0; var sawFalseWrite; function write() { if (++writes === 64) { clearTimeout(timer); sec.end(); test(); } else { timer = setTimeout(write); var writeRet = sec.write(new Buffer('hello')); // Once we find out that the connection is destroyed, every // write() returns false if (sawFalseWrite) assert.equal(writeRet, false); else sawFalseWrite = writeRet === false; } } assert.equal(first.connection, sec.connection, 'should reuse connection'); sec.on('response', function(res) { res.on('data', function(chunk) { console.error('second saw data: ' + chunk); }); res.on('end', function() { console.error('second saw end'); }); }); function test() { server.close(); assert(sec.connection.destroyed); if (sec.output.length || sec.outputEncodings.length) console.error('bad happened', sec.output, sec.outputEncodings); assert.equal(sec.output.length, 0); assert.equal(sec.outputEncodings, 0); assert(sawFalseWrite); assert(gotFirstResponse); assert(gotFirstData); assert(gotFirstEnd); console.log('ok'); } } });