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'); 24if (common.isWindows) 25 common.skip('This test is disabled on windows.'); 26 27const assert = require('assert'); 28const http = require('http'); 29const net = require('net'); 30 31switch (process.argv[2]) { 32 case 'child': return child(); 33} 34 35let ok; 36 37process.on('exit', function() { 38 assert.ok(ok); 39}); 40 41// WARNING: This is an example of listening on some arbitrary FD number 42// that has already been bound elsewhere in advance. However, binding 43// server handles to stdio fd's is NOT a good or reliable way to do 44// concurrency in HTTP servers! Use the cluster module, or if you want 45// a more low-level approach, use child process IPC manually. 46test(function(child, port) { 47 // Now make sure that we can request to the subprocess, then kill it. 48 http.get({ 49 server: 'localhost', 50 port: port, 51 path: '/', 52 }).on('response', function(res) { 53 let s = ''; 54 res.on('data', function(c) { 55 s += c.toString(); 56 }); 57 res.on('end', function() { 58 child.kill(); 59 child.on('exit', function() { 60 assert.strictEqual(s, 'hello from child\n'); 61 assert.strictEqual(res.statusCode, 200); 62 console.log('ok'); 63 ok = true; 64 }); 65 }); 66 }); 67}); 68 69function child() { 70 // Prevent outliving the parent process in case it is terminated before 71 // killing this child process. 72 process.on('disconnect', function() { 73 console.error('exit on disconnect'); 74 process.exit(0); 75 }); 76 77 // Start a server on fd=3 78 http.createServer(function(req, res) { 79 console.error('request on child'); 80 console.error('%s %s', req.method, req.url, req.headers); 81 res.end('hello from child\n'); 82 }).listen({ fd: 3 }, function() { 83 console.error('child listening on fd=3'); 84 process.send('listening'); 85 }); 86} 87 88function test(cb) { 89 const server = net.createServer(function(conn) { 90 console.error('connection on parent'); 91 conn.end('hello from parent\n'); 92 }).listen(0, function() { 93 const port = this.address().port; 94 console.error('server listening on %d', port); 95 96 const spawn = require('child_process').spawn; 97 const child = spawn(process.execPath, [__filename, 'child'], { 98 stdio: [ 0, 1, 2, server._handle, 'ipc' ] 99 }); 100 101 console.log('%j\n', { pid: child.pid }); 102 103 // Now close the parent, so that the child is the only thing 104 // referencing that handle. Note that connections will still 105 // be accepted, because the child has the fd open. 106 server.close(); 107 108 child.on('message', function(msg) { 109 if (msg === 'listening') { 110 cb(child, port); 111 } 112 }); 113 }); 114} 115