• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3const { ObjectDefineProperty } = primordials;
4const rawMethods = internalBinding('process_methods');
5
6// TODO(joyeecheung): deprecate and remove these underscore methods
7process._debugProcess = rawMethods._debugProcess;
8process._debugEnd = rawMethods._debugEnd;
9process._startProfilerIdleNotifier = rawMethods._startProfilerIdleNotifier;
10process._stopProfilerIdleNotifier = rawMethods._stopProfilerIdleNotifier;
11
12function defineStream(name, getter) {
13  ObjectDefineProperty(process, name, {
14    configurable: true,
15    enumerable: true,
16    get: getter
17  });
18}
19
20defineStream('stdout', getStdout);
21defineStream('stdin', getStdin);
22defineStream('stderr', getStderr);
23
24// Worker threads don't receive signals.
25const {
26  startListeningIfSignal,
27  stopListeningIfSignal
28} = require('internal/process/signal');
29process.on('newListener', startListeningIfSignal);
30process.on('removeListener', stopListeningIfSignal);
31
32// ---- keep the attachment of the wrappers above so that it's easier to ----
33// ----              compare the setups side-by-side                    -----
34
35const { guessHandleType } = internalBinding('util');
36
37function createWritableStdioStream(fd) {
38  let stream;
39  // Note stream._type is used for test-module-load-list.js
40  switch (guessHandleType(fd)) {
41    case 'TTY':
42      const tty = require('tty');
43      stream = new tty.WriteStream(fd);
44      stream._type = 'tty';
45      break;
46
47    case 'FILE':
48      const SyncWriteStream = require('internal/fs/sync_write_stream');
49      stream = new SyncWriteStream(fd, { autoClose: false });
50      stream._type = 'fs';
51      break;
52
53    case 'PIPE':
54    case 'TCP':
55      const net = require('net');
56
57      // If fd is already being used for the IPC channel, libuv will return
58      // an error when trying to use it again. In that case, create the socket
59      // using the existing handle instead of the fd.
60      if (process.channel && process.channel.fd === fd) {
61        stream = new net.Socket({
62          handle: process.channel,
63          readable: false,
64          writable: true
65        });
66      } else {
67        stream = new net.Socket({
68          fd,
69          readable: false,
70          writable: true
71        });
72      }
73
74      stream._type = 'pipe';
75      break;
76
77    default:
78      // Provide a dummy black-hole output for e.g. non-console
79      // Windows applications.
80      const { Writable } = require('stream');
81      stream = new Writable({
82        write(buf, enc, cb) {
83          cb();
84        }
85      });
86  }
87
88  // For supporting legacy API we put the FD here.
89  stream.fd = fd;
90
91  stream._isStdio = true;
92
93  return stream;
94}
95
96function dummyDestroy(err, cb) {
97  cb(err);
98
99  // We need to emit 'close' anyway so that the closing
100  // of the stream is observable. We just make sure we
101  // are not going to do it twice.
102  // The 'close' event is needed so that finished and
103  // pipeline work correctly.
104  if (!this._writableState.emitClose) {
105    process.nextTick(() => {
106      this.emit('close');
107    });
108  }
109}
110
111let stdin;
112let stdout;
113let stderr;
114
115function getStdout() {
116  if (stdout) return stdout;
117  stdout = createWritableStdioStream(1);
118  stdout.destroySoon = stdout.destroy;
119  // Override _destroy so that the fd is never actually closed.
120  stdout._destroy = dummyDestroy;
121  if (stdout.isTTY) {
122    process.on('SIGWINCH', () => stdout._refreshSize());
123  }
124  return stdout;
125}
126
127function getStderr() {
128  if (stderr) return stderr;
129  stderr = createWritableStdioStream(2);
130  stderr.destroySoon = stderr.destroy;
131  // Override _destroy so that the fd is never actually closed.
132  stderr._destroy = dummyDestroy;
133  if (stderr.isTTY) {
134    process.on('SIGWINCH', () => stderr._refreshSize());
135  }
136  return stderr;
137}
138
139function getStdin() {
140  if (stdin) return stdin;
141  const fd = 0;
142
143  switch (guessHandleType(fd)) {
144    case 'TTY':
145      const tty = require('tty');
146      stdin = new tty.ReadStream(fd, {
147        highWaterMark: 0,
148        readable: true,
149        writable: false
150      });
151      break;
152
153    case 'FILE':
154      const fs = require('fs');
155      stdin = new fs.ReadStream(null, { fd: fd, autoClose: false });
156      break;
157
158    case 'PIPE':
159    case 'TCP':
160      const net = require('net');
161
162      // It could be that process has been started with an IPC channel
163      // sitting on fd=0, in such case the pipe for this fd is already
164      // present and creating a new one will lead to the assertion failure
165      // in libuv.
166      if (process.channel && process.channel.fd === fd) {
167        stdin = new net.Socket({
168          handle: process.channel,
169          readable: true,
170          writable: false,
171          manualStart: true
172        });
173      } else {
174        stdin = new net.Socket({
175          fd: fd,
176          readable: true,
177          writable: false,
178          manualStart: true
179        });
180      }
181      // Make sure the stdin can't be `.end()`-ed
182      stdin._writableState.ended = true;
183      break;
184
185    default:
186      // Provide a dummy contentless input for e.g. non-console
187      // Windows applications.
188      const { Readable } = require('stream');
189      stdin = new Readable({ read() {} });
190      stdin.push(null);
191  }
192
193  // For supporting legacy API we put the FD here.
194  stdin.fd = fd;
195
196  // `stdin` starts out life in a paused state, but node doesn't
197  // know yet. Explicitly to readStop() it to put it in the
198  // not-reading state.
199  if (stdin._handle && stdin._handle.readStop) {
200    stdin._handle.reading = false;
201    stdin._readableState.reading = false;
202    stdin._handle.readStop();
203  }
204
205  // If the user calls stdin.pause(), then we need to stop reading
206  // once the stream implementation does so (one nextTick later),
207  // so that the process can close down.
208  stdin.on('pause', () => {
209    process.nextTick(onpause);
210  });
211
212  function onpause() {
213    if (!stdin._handle)
214      return;
215    if (stdin._handle.reading && !stdin.readableFlowing) {
216      stdin._readableState.reading = false;
217      stdin._handle.reading = false;
218      stdin._handle.readStop();
219    }
220  }
221
222  return stdin;
223}
224
225// Used by internal tests.
226rawMethods.resetStdioForTesting = function() {
227  stdin = undefined;
228  stdout = undefined;
229  stderr = undefined;
230};
231