Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I close stdin in Node?

I am learning Node.js and thought I had a very simple script but no about of tweaking will ever get my script from hanging forever.

Say I have a dumb server running:

$ nc -l 32001 <<EOF
HTTP/1.1 200 OK
Content-Type: text/plain

Works
EOF

And I run the following script:

var http = require('http');
var options = {
  hostname: 'localhost',
  port: 32001,
  method: 'POST',
  headers: {'Content-Type': 'text/plain'}
};
var req = http.request(options, res => {
  var exitCode = res.statusCode >= 200 && res.statusCode < 300 ? 0 : 1;
  res.pipe(process.stdout).on('end', () => process.exit(exitCode));
});
req.on('error', error => console.error(error));
process.stdin.pipe(req)
  .on('end', () => console.log('this does trigger'));

But when I perform the following:

$ echo foobar | node my-script.js

It just hangs and never reaches the request callback. I would expect the req stream to end and the http.request callback to be called and then that outputs Works and finally exits the process.

I've check that the end event is indeed called from process.stdin.pipe() and I have attempted to manually end the req stream in the end callback. But it just will not end. How do I pipe stdin to an http.request and still have it end the stream?

like image 496
Sukima Avatar asked Feb 22 '18 18:02

Sukima


People also ask

How do I end a Stdin process?

Alternatively, after typing the input into shell, you can press Ctrl + D to send EOF (end-of-file) to trigger the event handler in process. stdin. on("end", ...)

How do I close a stdin stream?

I understand that since it inherits from stream, one should know that `pause` is how to "close" it, but for the sake of clarity for people who haven't had enough of their coffee or cocoa yet that day I would suggest adding: `process. stdin. pause` will "close" `stdin`.

What is Stdin NodeJS?

The stdin property of the process object is a Readable Stream. It uses on() function to listen for the event.

What is process Stdin resume ()?

process. stdin. resume() A Readable Stream that points to a standard input stream (stdin). Standard input streams are paused by default, so you must call process.


1 Answers

You are on the right track; you just need to attach your listeners to the proper object events. In the first case (as written, not as executed):

res.pipe(process.stdout).on('end', () => process.exit(exitCode));

What you said: "Pipe the data from response to stdout, and when stdout ends, exit the process."

What you meant: "Pipe the data from response to stdout. When response ends, exit the process." Codified:

res.pipe(process.stdout);
res.on('end', () => process.exit(exitCode));

The point of clarity here is that unless you specifically close process.stdout, it will never close/end until you exit the program. The response however, will end when the HTTP interaction is complete.

It goes similar for the second case:

process.stdin.pipe(req)
  .on('end', () => console.log('this does trigger'));

What you said: "Pipe the data from stdin to request, and when request ends, write a message."

What you meant: "Pipe the data from stdin to request. When stdin ends, write a message." Codified:

process.stdin.pipe(req);
process.stdin.on('end', () => console.log('this does trigger'));

It's slightly more nuanced here because you could listen for either stdin's end event or the request's finish event:

process.stdin.pipe(req).on('finish', () => console.log('Request has finished writing/sending');
process.stdin.on('end', () => console.log('Stdin has no more data'));

For completeness then, your working client back to you, with some mild text modifications for assumed pedagogical clarity:

var http = require('http');
var options = {
  hostname: 'localhost',
  port: 32001,
  method: 'POST',
  headers: {'Content-Type': 'text/plain'}
};
var req = http.request(options, res => {
  var exitCode = res.statusCode >= 200 && res.statusCode < 300 ? 0 : 1;
  res.pipe(process.stdout);
  res.on('end', () => {
    console.log('Response (IncomingMessage) has no more data; exiting with code:', exitCode);
    process.exit(exitCode);
  });
});
req.on('error', error => console.error(error));
process.stdin.on('end', () => console.log('Stdin has no more data.'));
process.stdin.pipe(req).on('finish', () => console.log('Request has finished writing/sending'));

Which outputs at command line:

$ echo Some text from stdin | node test.js; echo $?
Stdin has no more data.
Request has finished writing/sending
Works
Response (IncomingMessage) has no more data; exiting with code: 0
0

And at "the server":

$ nc -l 32001 <<EOF
HTTP/1.1 200 OK
Content-Type: text/plain

Works
EOF
POST / HTTP/1.1
Content-Type: text/plain
Host: localhost:32001
Connection: close
Transfer-Encoding: chunked

15
Some text from stdin

0
like image 181
hunteke Avatar answered Oct 26 '22 09:10

hunteke