run shell command and display in http server - node.js

I want to run some predefined shell commands and return them as plain text in a http server.
The content written at (1) is being served to my browser, but the content at (2) which eventually has to be the stdout is not being served. Can anybody help me how to achieve this?
var http = require('http'),
url = require('url'),
exec = require('child_process').exec,
child,
poort = 8088;
http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
var pathname = url.parse(req.url).pathname;
if (pathname == '/who'){
res.write('Who:'); // 1
child = exec('who',
function(error, stdout, stderr){
res.write('sdfsdfs'); //2
})
} else {
res.write('operation not allowed');
}
res.end();
}).listen(poort);

It's because of where you place res.end().
Since exec is asynchronous, res.end() actually happens before the res.write you label as (2). No more writes can be issued after an .end, so the browser doesn't get any further data.
You should call res.end() inside the exec callback, after res.write. The exec callback will be issued when the child process terminates and will get the complete output.

Related

Can I cancel a HTTP response after headers are sent?

On a node HTTP server I'm spawning a process and streaming the output to the response.
When the process returns I'd like to indicate to the client if an error occured. Obviously I can't set the HTTP status code as the headers were already sent.
Is there a way to abort the connection?
E.g.
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('Hello World\n');
// how do I abort the request at this point
// and indicate an error to the client?
// e.g. curl should return != 0
res.end();
}).listen(1337, '127.0.0.1');
I found this in google groups, you can use
either req.client.destroy();
or res.connection.destroy();
curl will then report
curl: (18) transfer closed with outstanding read data remaining
var thirdPartyApp = $express();
thirdPartyApp.use('/error/', function (req, res) {
console.log('error');
res.writeHead(200);
res.write('aye');
throw 'booboo!';
res.end();
});
On expressjs this does not kill the node process (probably just need to bind to the error event) but does immediately kill the response, indicating an error to the user without a timeout.

Node.js double console.log output

I'm learning Node.js and I'd like to understand the "why" when code spits out duplicated console.log outputs but only a single response.write outputs.
Heres my simple code example:
var http = require('http');
http.createServer(function(request, response){
response.writeHead(200, {'Content-type': 'text/plain'});
console.log('hello 1');
response.write('Hello world');
console.log('hello 2');
response.end();
}).listen(8000);
And on my console/terminal I get:
hello 1
hello 2
hello 1
hello 2
Thanks.
Some browsers also send a request to locate the favicon.ico file. Since the file isn't present by default, a browser(Chrome in particular) will always send two requests: one for the originally requested file and another for favicon.ico. This is a known bug in Chrome and has been fixed in version 29. Firefox, however, requests for favicon.ico only for the first request. If you console.log the request URI path, you must see a request to localhost:8000/favicon.ico.
var http = require('http');
http.createServer(function(request, response){
response.writeHead(200, {'Content-type': 'text/plain'});
if(request.url === '/favicon.ico') {
console.log('Favicon was requested');
}
console.log('hello 1');
response.write('Hello world');
console.log('hello 2');
response.end();
}).listen(8000);
I've had the same problem myself, and I found out that using something like
var http = require('http');
http.createServer(function(req,res) {
if(req.url === '/favicon.ico')
{
//everything here is ignored
}
res.writeHead(200,{"Content-Type": "text/plain"});
res.write("Hello World\n");
res.end();
console.log("Connection made");
}).listen(1337, "127.0.0.1");
console.log("Server running at http://127.0.0.1:1337/");
is enough to avoid that behaviour. For some reason, when I check req.url and compare it to '/favicon.ico' nothing is sent to console, in fact, everything in that block is ignored. I don't know if this behaviour is expected, but you sure could try it.
If you output the header you're telling the server that you found favicon, hence the response is processed and no matter what you get that double console.log(). Instead, end it before sending a writeHead() or send a 404.
var http = require('http');
http.createServer(function (req, res) {
if(req.url === '/favicon.ico') {
res.writeHead(404);
res.end();
} else {
res.writeHead(200, {'Content-Type': 'text/plain'});
}
//code here...
res.end();
}
i think that this problem still persists in chrome Version 67.0.3396.87 (32-bit) because when i ran my nodeJS script i saw 2 console.log() statements one was able to print out the query the other was not, so i corrected my code so as to see console.log() statements only once, it was simple all i had to do was add a return statement if the request.url was == (equal to)"/favicon.ico" in the beginning of the code and everything worked fine
previous code
var http = require('http');
var url = require('url');
http.createServer((request,response)=>{
var q = url.parse(request.url,true).query;
console.log(request.url);
console.log('hey there! we got a request from '+q.name+' !');
}).listen(8080);
and the output was :
/?name=harshit
hey there we got a request from harshit !
/favicon.ico
hey there we got a request from undefined !
code after debugging :
var http = require('http');
var url = require('url');
http.createServer((request,response)=>{
if(request.url == "/favicon.ico"){
return ;
}
var q = url.parse(request.url,true).query;
console.log(request.url);
console.log('hey there! we got a request from '+q.name+' !');
}).listen(8080);
output :
/?name=harshit
hey there we got a request from : harshit !
in a nutshell the duplication as it is mentioned before is a result of the favicon request so to avoid this problem, I propose you this simple snipet:
var pathname = url.parse(request.url).pathname;
if(pathname != '/favicon.ico')
console.log('hello 1');
It can also be a Chrome plugin like JSONView. I was just trying to figure it out until I tried incognito and realized it was no longer causing the problem. Also was requesting a JSON file.

Node.js HTTP Server Stops Listening

I have an HTTP server setup on port 1338 to listen on the IP for the server. This works just fine when I first launch Node, but for some reason I have run into issues where the server randomly stops listening. I have checked the logs that Forever is collecting from my app including any uncaught exceptions. Nothing shows up in the logs of having any error since startup.
My question is two fold. What would cause the server to stop listening at random intervals? Also what check should be running in Node so that I can log out the error that is causing the listener to stop?
Here is the code below for my HTTP Server.
http.createServer(function (req, res) {
var pathname = url.parse(req.url).pathname;
var query = url.parse(req.url, true).query;
var check;
var responseData = '';
if(pathname === '/healthcheck/ticket'){
check = new Date().getTime();
check = check - tickets.lastAction;
if(check < 30000){
responseData = "page ok";
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(responseData);
}
else{
check = check/1000;
responseData = 'Last action taken by the Ticket Generator was ' + check + ' seconds ago';
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(responseData);
}
}
else{
responseData = 'URL NOT FOUND!';
res.writeHead(404, {'Content-Type': 'text/plain'});
res.end(responseData);
}
}).listen(config.eng.port, config.eng.host);
You don't handle the case when pathname is not equal to /healthcheck/ticket. There is no else branch.
Hence, when your server gets called with other urls but /healthcheck/ticket, it never closes the res stream, as res.end() is never called.
After a while, your server runs out of (network) resources, and hence seems to hang (i.e., it does not react on new requests any longer).
The solution is simple: Provide an else branch, and call res.end() in it, and everything should be fine.

FFMPEG hangs the whole nodejs process

What I am trying to do is to make a thumbnail of a video using ffmpeg. The video data is received in a HTTP request and then piped to ffmpeg. The problem is that once the ffmpeg child process exits I simply can't send the response back.
Here is the code:
var http = require('http'),
sys = require('sys'),
child = require('child_process')
http.createServer(function (req, res) {
im = child.spawn('ffmpeg',['-i','-','-vcodec','mjpeg','-ss','00:00:03','-vframes','1','-s','100x80','./thumb/thumbnail.jpg']);
im.on('exit', function (code, signal) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('{"success":true}\n');
});
req.connection.pipe(im.stdin);
}).listen(5678, "127.0.0.1");
The problem is that calling:
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('{"success":true}\n');
does nothing, the client never receives the response.
After two days of debugging and googling It seems like I have found the problem.
There are two related open bugs in node.js responsible:
https://github.com/joyent/node/issues/777
https://github.com/joyent/node/issues/782
I will try to describe what I think the problem is with the 'pipe' method:
The request stream fails to invoke end on ffmpeg.stdin (probably bug #777), this causes a broken pipe error, but node.js doesn't handle the error because of bug #782, meanwhile the request stream remains paused - this blocks any response from being sent.
The hack/workaround is to resume the request stream once ffmpeg exits.
Here is the fixed code sample:
var http = require('http'),
sys = require('sys'),
child = require('child_process')
http.createServer(function (req, res) {
im = child.spawn('ffmpeg',['-i','-','-vcodec','mjpeg','-ss','00:00:03','-vframes','1','-s','100x80','./thumb/thumbnail.jpg']);
im.on('exit', function (code, signal) {
req.resume();
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('{"success":true}\n');
});
req.connection.pipe(im.stdin);
}).listen(5678, "127.0.0.1");
Please keep in mind that this is a hack/workaround and may lead to problems with future node.js releases once they do something about those bugs
I would try something like this.
var http = require('http'):
var sys = require('sys'):
var child = require('child_process'):
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
im = child.spawn('ffmpeg',['-i','-','-vcodec','mjpeg','-ss','00:00:03','-vframes','1','-s','100x80','./thumb/thumbnail.jpg']);
im.on('exit', function (code, signal) {
res.end('{"success":true}\n');
});
req.connection.pipe(im.stdin);
}).listen(5678, "127.0.0.1");
You are trying to pipe out data to the socket before sending the header.

Nodejs - Stream output to browser

var http = require("http");
var sys = require('sys')
var filename = process.ARGV[2];
var exec = require('child_process').exec;
var com = exec('uptime');
http.createServer(function(req,res){
res.writeHead(200,{"Content-Type": "text/plain"});
com.on("output", function (data) {
res.write(data, encoding='utf8');
});
}).listen(8000);
sys.puts('Node server running')
How do I get the data streamed to the browser ?
If you're just generally asking whats going wrong, there are two main things:
You're using child_process.exec() incorrectly
You never called res.end()
What you're looking for is something more like this:
var http = require("http");
var exec = require('child_process').exec;
http.createServer(function(req, res) {
exec('uptime', function(err, stdout, stderr) {
if (err) {
res.writeHead(500, {"Content-Type": "text/plain"});
res.end(stderr);
}
else {
res.writeHead(200,{"Content-Type": "text/plain"});
res.end(stdout);
}
});
}).listen(8000);
console.log('Node server running');
Note that this doesn't actually require 'streaming' in the sense that the word is generally used. If you had a long running process, such that you didn't want to buffer stdout in memory until it completed (or if you were sending a file to the browser, etc), then you would want to 'stream' the output. You would use child_process.spawn to start the process, immediately write the HTTP headers, then whenever a 'data' event fired on stdout you would immediately write the data to HTTP stream. On an 'exit' event you would call end on the stream to terminate it.

Resources