Saving image to node.js server without express.js - javascript

So I have been wondering how to save an image to node.js server without the use of express.(just learning node and want to make everything myself to learn node better, without express).
So far I have a form with the image as only input which I send with a post request. This is what I have so far on my server, which does not log anything.
if(req.method === 'POST') {
if (req.url === '/upload') {
req.on('error', function(e) {
console.log('Problem with request: ' + e.message);
});
res.writeHead(200, {'Content-Type': 'image/jpg; charset=utf8'});
req.on('data', function (chunk) {
fs.writeFile(__dirname + "/uploads/dada.jpg", chunk, function(err) {
if(err) {
console.log(err);
} else {
console.log("The file was saved!");
}
});
});
}
}
This is my form:
<form method="post" action="/upload" enctype="multipart/form-data">
EDIT: I fixed most of the problems, but the file is only saved as an image, but cannot be viewed like one. (Something is wrong with the content-type I guess, but don't know how to fix it)
Here is fiddle of my whole app. I know I need to separate it in different modules, but I will do that later

I completely forgot about this old question but now that I see it has quite some views, here is the solution I found:
var port = 1357;
var http = require('http'),
path = require('path'),
mime = require('mime'),
fs = require('fs'),
GUID = require('GUID'),
formidable = require('formidable'),
util = require('util');
var app = http.createServer(function (req, res) {
if (req.method === 'POST') {
if (req.url === '/upload') {
req.on('error', function (e) {
console.log('Problem with request: ' + e.message);
});
var fileDirectory = __dirname + '/db/',
form = new formidable.IncomingForm();
form.keepExtensions = true;
form.uploadDir =fileDirectory;
form.parse(req, function (err, fields, files) {
if (err) throw (err);
var pic = JSON.stringify(util.inspect(files)),
upIndx = pic.indexOf('db'),
path = pic.slice(upIndx + 6, upIndx + 42);
res.writeHead(200, {
'Content-Type': 'text/html'
});
fs.readFile('views/index.html', function (err, page) {
res.writeHead(200, {
'Content-Type': 'text/html'
});
res.write(page);
res.write('<div>Download Link: </div><div>' + fileDirectory + path + '</div>');
res.end();
});
});
}
} else {
//not important for question, handle other request
}
});
app.listen(port);
console.log('Server running on port: ' + port)

Related

Simple Node.js server without Express - piping HTML files to response

I am trying my hand at making a simple Node.js server without Express and this where I actually learn a bit more about the down and dirty of actually server files and data on requests based on paths request and basic HTTP stuff.
I have this straightforward server like so:
var http = require('http');
const PORT = 6969;
var allRoutes = require('./routes/all');
var server = http.createServer(allRoutes);
server.listen(PORT, function () {
console.log("Server listening on: http://localhost:%s", PORT);
});
and then I have one "middleware" function like so that handles all requests:
var url = require('url');
var fs = require('fs');
var appRootPath = require('app-root-path');
var path = require('path');
function handleRequest(req, res) {
var requestUrl = url.parse(req.url);
var fsPath;
if (requestUrl.pathname === '/') {
fsPath = path.resolve(appRootPath + '/view/index.html');
}
else {
fsPath = path.resolve(appRootPath + '/view/' + requestUrl.pathname);
}
fs.stat(fsPath, function (err, stat) {
if (err) {
console.log('error occurred...' + err);
return end(req, res);
}
try {
if (stat.isFile()) {
res.writeHead(200);
fs.createReadStream(fsPath).pipe(res);
}
else {
res.writeHead(500);
}
}
finally {
end(req, res);
}
});
}
function end(req, res) {
res.end();
}
module.exports = handleRequest;
the problem I am having is that my function doesn't seem to pipe the response to the browser. The browser shows no evidence of the data come from index.html, which is a barebones .html HTML5 file.
I stole the example, and am surprised it's not really working. Anyone have an idea? I know for sure that the fs.stat function is not experiencing an error and then it is streaming the index.html file, it just doesn't seem to be streaming to the right place...
For starters:
if (requestUrl.pathname = '/')
should be:
if (requestUrl.pathname === '/')
Your code was assigning, not comparing.
In addition, the .pipe() is asynchronous, but you are calling res.end() BEFORE it gets to do it's job in your finally{} block which closes the response stream and stops your pipe from doing anything. By default .pipe() will close the write stream by itself, so you don't need the res.end() at all when using .pipe().
You can change the code to this:
var url = require('url');
var fs = require('fs');
var appRootPath = require('app-root-path');
var path = require('path');
function handleRequest(req, res) {
var requestUrl = url.parse(req.url);
var fsPath;
if (requestUrl.pathname === '/') {
fsPath = path.resolve(appRootPath + '/view/index.html');
}
else {
fsPath = path.resolve(appRootPath + '/view/' + requestUrl.pathname);
}
fs.stat(fsPath, function (err, stat) {
if (err) {
console.log('error occurred...' + err);
return end(req, res);
}
try {
if (stat.isFile()) {
res.writeHead(200);
fs.createReadStream(fsPath).pipe(res);
}
else {
res.writeHead(500);
end(req.res);
}
}
catch(e) {
end(req, res);
}
});
}
function end(req, res) {
res.end();
}
module.exports = handleRequest;

Node.js error "terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc"

I am using node.js on digital ocean and trying to run a file upload / download server.
To make sure the server runs in the background and does not quit on error, I am using the following
nohup nodejs server.js &
I am using nodejs instead of the node command because that is what digital ocean recommends.
This server is almost exlusively for uploading and downloading files. This works, for about two files, but then the server crashes with the following error:
"terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc"
I have no idea what is causing this, and I would appreciate any help. Preventing the crash would be great but also making it so the node server would not crash would also be great. I thought that is what nohup does, but apparently not. (I also haven't been able to get forever working correctly).
Here is the code for my server:
var http = require('http'),
url = require('url'),
util = require('util'),
path = require('path'),
fs = require('fs'),
qs = require('querystring');
var formidable = require('formidable'),
mime = require('mime');
var account = {username: 'test', password: 'etc'};
var accounts = [account],
port = 9090,
function dirTree(filename) {
var stats = fs.lstatSync(filename),
info = {
name: path.basename(filename),
path: ip + ':' + port + '/uploads/finished/' + path.basename(filename),
type: mime.lookup(filename).substring(0, 5)
};
if (stats.isDirectory()) {
info.type = "folder";
info.children = fs.readdirSync(filename).map(function(child) {
return dirTree(filename + '/' + child);
});
}
return info;
}
http.createServer(function(request, response) {
if(request.method.toLowerCase() == 'get') {
var filePath = './content' + request.url;
if (filePath == './content/') {
filePath = './content/home.html';
}
if (filePath == './content/feed') {
a = dirTree('./content/uploads/finished');
response.end(JSON.stringify(a));
}
var extname = path.extname(filePath);
var contentType = mime.lookup(extname);
fs.exists(filePath, function (exists) {
if (exists) {
fs.readFile(filePath, function (error, content) {
if (error) {
response.writeHead(500);
response.end();
}
else {
response.writeHead(200, {'Content-Type': contentType});
response.end(content, 'utf-8');
}
})
} else {
response.writeHead(404);
response.end();
}
});
}
if (request.method.toLowerCase() == 'post') {
var form = new formidable.IncomingForm;
if (request.url == '/verify') {
form.parse(request, function (err, fields, files) {
for (i = 0; i < accounts.length; i++) {
if (fields.username == accounts[i].username && fields.password == accounts[i].password) {
fs.readFile('./content/uploadForm.html', function (error, content) {
if (error) {
response.end('There was an error');
} else {
response.end(content);
}
});
} else {
fs.readFile('./content/invalidLogin.html', function (error, content) {
if (error) {
response.end('There was an error');
} else {
response.end(content);
}
});
}
}
});
} else if (request.url == '/upload') {
var oldPath,
newPath,
fileName;
form.uploadDir = './content/uploads/temp/';
form.keepExtensions = true;
form.parse(request, function (err, fields, files) {
type = files['upload']['type'];
fileName = files['upload']['name'];
oldPath = files['upload']['path'];
newPath = './content/uploads/finished/' + fileName;
});
form.on('end', function () {
fs.rename(oldPath, newPath, function (err) {
if (err) {
response.end('There was an error with your request');
console.log('error')
} else {
response.end('<h1>Thanks for uploading ' + fileName + '<h1>');
}
});
});
}
}
}).listen(port);
console.log('listening on ' + port);
It looks like your script is just run out of the available memory.
Most likely you upload or download very large file and you read complete file in memory while receiving or sending.
You should rewrite you code using stream operations and process files chunk-by-chunk instead.

Basic attempt at using NodeJS

I tried to follow an example on the web for creating a NodeJS server and router, but have ran into problems. What follows is primarily the example with a bit of other code.
Index.js
var server = require("./server");
var router = require("./router");
server.start(router.route);'
Router.js
var fs = require("fs");
function route(filename) {
fs.readFile(filename, 'utf8', function (err, data) {
if (err) {
console.log('Error: ' + err);
return;
}
console.log("About to route a request for " + filename);
data = JSON.parse(data);
})
}
exports.route = route;
Server.js
var http = require('http');
var url = require("url");
function start(route) {
function onRequest(request, response) {
var filename = request.url.substr(1);
// call for specific json file here
if (filename == "favicon.ico") {
response.writeHead(200, {'Content-Type': 'image/x-icon'} );
response.end();
console.log('favicon requested');
return;
}
else {
filename += ".json";
console.log("Request for " + filename + " received.");
response.writeHead(200, { 'Content-Type': 'application/json', "Access-Control-Allow-Origin":"*" });
response.write("" + route(filename),0,4);
response.end();
}
}
http.createServer(onRequest).listen(8124);
}
exports.start = start;
console.log('Server running at http://127.0.0.1:8124/');
The question I have is, among others, how does the route command work?
What I get when I browse to the server is 'undefined'. How do I get the actual json from the Router?
I tried: var result = route(filename); but that failed badly.
In essence, how to get the data from the router and write it to the response. If you haven't guessed, javascript and NodeJS is rather new to me.
Any pointers would be greatly appreciated.
Thank you.
Your route function has an async method, fs.readFile. You'll need to pass in a callback to the route function, so that it can return the data properly. Otherwise, route will return immediately with no data (since it's async) regardless if you have a return statement inside readFile.
router.js
function route(filename, callback) {
fs.readFile(filename, 'utf8', function (err, data) {
if (err) {
console.log('Error: ' + err);
return;
}
console.log("About to route a request for " + filename);
data = JSON.parse(data);
callback(data); // Call this function after the data is grabbed.
})
}
server.js portion:
response.writeHead(200, { 'Content-Type': 'application/json', "Access-Control-Allow-Origin":"*" });
route(filename, function (data) {
response.write("" + JSON.stringify(data),0,4);
response.end();
});

node + socket.io: multiple server emits for single client emit?

I've just managed to connect to a server script with socket.io, so I'm happy about that. I'm less happy though about the weird behavior my script generates: I send one emit to the server script on a buttonclick, and the server test script sends back a message 6x to the console log. Googling this problem description gets ideas about spotty, repeating connections, but I don't think that's it.
Anyway, here's the client app.js:
var commentapp={
init: function(){
var commentapp=this;
commentapp.btn_api=$('#btn_api');
commentapp.btn_api.click(this.get_comment_data);
},
get_comment_data: function(btn_event){
var commentapp=this;
console.log('trying to connect');
commentapp.socket=io.connect('http://localhost:8080');
commentapp.socket.on('connect', function() {
commentapp.socket.emit('btn_api_call');
}); //commentapp.socket.on 'connect',
commentapp.socket.on('serverMessage', function(content){
console.log(content);
}
); //commentapp.socket.on('serverMessage'
}
};
$(function() {
commentapp.init();
});
The server script is as follows:
var httpd = require("http").createServer(handler);
var io=require('/Users/user/Virtualenvs/node_modules/socket.io/lib/socket.io').listen(httpd);
var fs = require('fs');
var url = require("url");
var path = require("path");
var port = process.argv[2] || 8080;
httpd.listen(parseInt(port, 10));
function handler (request, response) {
var uri = url.parse(request.url).pathname,
filename = path.join(process.cwd(), uri);
console.log(uri);
path.exists(filename, function(exists) {
if(!exists) {
response.writeHead(404, {"Content-Type": "text/plain"});
response.write("404 Not Found\n");
response.end();
return; //these returns get you out of the function I think
}
if (fs.statSync(filename).isDirectory()) filename += '/index.html';
fs.readFile(filename, "binary", function(err, file) {
if(err) {
response.writeHead(500, {"Content-Type": "text/plain"});
response.write(err + "\n");
response.end();
return;
}
response.writeHead(200);
response.write(file, "binary"); //otherwise here's where the file gets finally served
response.end();
}); //fs.readFile
}); //path.exists
io.sockets.on('connection',function(socket) {
socket.on('btn_api_call', function() {
socket.emit('serverMessage', 'Server heard you.');
});
});
};
console.log("Static file server running at\n => http://localhost:" + port + "/\nCTRL + C to shutdown");
Both of these are cannibalized from https://github.com/accbel/nodejs-socketio-example and Pedro Teixeira's book.
So if I click the button to generate the 'btn_api_call'emit, the console log will say "'Server heard you.'" 6x. Hopefully this is a rookie mistake easily set straight.
Thanks for your help!
This is likely due to having your registration for connections inside of a route handler.
Each time a request comes in that is handled by that route, the code is adding a new listener for connections.
You likely have a similar problem in your client - connecting each time the button is clicked.
Move your connection listener outside the route like this:
function handler (request, response) {
var uri = url.parse(request.url).pathname,
filename = path.join(process.cwd(), uri);
console.log(uri);
path.exists(filename, function(exists) {
if(!exists) {
response.writeHead(404, {"Content-Type": "text/plain"});
response.write("404 Not Found\n");
response.end();
return; //these returns get you out of the function I think
}
if (fs.statSync(filename).isDirectory()) filename += '/index.html';
fs.readFile(filename, "binary", function(err, file) {
if(err) {
response.writeHead(500, {"Content-Type": "text/plain"});
response.write(err + "\n");
response.end();
return;
}
response.writeHead(200);
response.write(file, "binary"); //otherwise here's where the file gets finally served
response.end();
}); //fs.readFile
}); //path.exists
};
io.sockets.on('connection',function(socket) {
socket.on('btn_api_call', function() {
socket.emit('serverMessage', 'Server heard you.');
});
});
On the client move the connect logic to init - something like:
var commentapp={
init: function(){
var commentapp=this;
commentapp.btn_api=$('#btn_api');
commentapp.btn_api.click(this.get_comment_data);
console.log('trying to connect');
commentapp.socket=io.connect('http://localhost:8080');
commentapp.socket.on('connect', function() {
commentapp.socket.emit('btn_api_call');
}); //commentapp.socket.on 'connect',
commentapp.socket.on('serverMessage', function(content){
console.log(content);
}
); //commentapp.socket.on('serverMessage'
},
get_comment_data: function(btn_event){
var commentapp=this;
commentapp.socket.emit('btn_api_call');
}
};

how to serve a file (exe or rar ) to a client for download from node.js server?

I have a a node.js server that serves an index.html with a text input for a password.
After a serverside password check the download should start for the client.
The client shouldn't be able to see the location path where the file lies on the server.
here is my server.js:
var
http = require('http'),
qs = require('querystring'),
fs = require('fs') ;
console.log('server started');
var host = process.env.VCAP_APP_HOST || "127.0.0.1";
var port = process.env.VCAP_APP_PORT || 1337;
http.createServer(function (req, res) {
if(req.method=='GET') {
console.log ( ' login request from ' + req.connection.remoteAddress );
fs.readFile(__dirname +'/index.html', function(error, content) {
if (error) {
res.writeHead(500);
res.end();
}
else {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(content, 'utf-8');
}
});
} // method GET end
else{ // method POST start
console.log('POST request from ' + req.connection.remoteAddress);
var body = '';
req.on('data', function (data) {
body += data;
if (body.length > 500) {
// FLOOD ATTACK OR FAULTY CLIENT, NUKE REQUEST
req.connection.destroy(); console.log('too much data')}
});
req.on('end', function () {
var postdata = qs.parse(body);
var password = postdata.passwordpost ;
if (password == '7777777') {
console.log('the password is right, download starting');
// ??????????????????????????????????? here I need help from stackoverflow
}
else{
console.log ('password wrong');
fs.readFile(__dirname +'/wrongpassword.html', function(error, content) {
if (error) {
res.writeHead(500);
res.end();
}
else {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(content, 'utf-8');
}
});
}
}); // req on end function end
}
}).listen(port, host);
the part where I need help is marked with ????????
here is my index.html:
<html>
<body>
<br> <br>
please enter your password to start your download
<br> <br>
<form method="post" action="http://localhost:1337">
<input type="text" name="passwordpost" size="50"><br><br>
<input type="submit" value="download" />
</form>
</body>
</html>
Do you know how to do this?
Sure, you can use this in your code :
res.setHeader('Content-disposition', 'attachment; filename='+filename);
//filename is the name which client will see. Don't put full path here.
res.setHeader('Content-type', 'application/x-msdownload'); //for exe file
res.setHeader('Content-type', 'application/x-rar-compressed'); //for rar file
var file = fs.createReadStream(filepath);
//replace filepath with path of file to send
file.pipe(res);
//send file
You needs to declare and require the path: path = require("path")
then can do:
var uri = url.parse(request.url).pathname
, filename = path.join(process.cwd(), uri);
path.exists(filename, function(exists) {
if(!exists) {
response.writeHead(404, {"Content-Type": "text/plain"});
response.write("404 Not Found\n");
response.end();
return;
}
response.writeHead(200);
response.write(file, "binary");
response.end();
}
check these complete example.
If you are willing to use express web framework, then it can be done in a much easier way.
app.get('/download', function(req, res){
var file = __dirname + 'learn_express.mp4';
res.download(file); // Sets disposition, content-type etc. and sends it
});
Express download API
I found some additional information about fs.createReadStream() ( especially error handling ) here and combined it with the answer of user568109. Here is my working downloadserver:
var
http = require('http'),
qs = require('querystring'),
fs = require('fs') ;
console.log('server started');
var host = process.env.VCAP_APP_HOST || "127.0.0.1";
var port = process.env.VCAP_APP_PORT || 1337;
http.createServer(function (req, res) {
if(req.method=='GET') {
console.log ( ' login request from ' + req.connection.remoteAddress );
fs.readFile(__dirname +'/index.html', function(error, content) {
if (error) {
res.writeHead(500);
res.end();
}
else {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(content, 'utf-8');
}
});
} // method GET end
else{ // method POST start
console.log('POST request from ' + req.connection.remoteAddress);
var body = '';
req.on('data', function (data) {
body += data;
if (body.length > 500) {
// FLOOD ATTACK OR FAULTY CLIENT, NUKE REQUEST
req.connection.destroy(); console.log('too much data')}
});
req.on('end', function () {
var postdata = qs.parse(body);
var password = postdata.passwordpost ;
if (password == '7777777') {
console.log('the password is right, download starting');
res.setHeader('Content-disposition', 'attachment; filename='+'test1.exe');
//filename is the name which client will see. Don't put full path here.
res.setHeader('Content-type', 'application/x-msdownload'); //for exe file
res.setHeader('Content-type', 'application/x-rar-compressed'); //for rar file
var readStream = fs.createReadStream('/test1.exe');
//replace filepath with path of file to send
readStream.on('open', function () {
// This just pipes the read stream to the response object (which goes to the client)
readStream.pipe(res);
});
// This catches any errors that happen while creating the readable stream (usually invalid names)
readStream.on('error', function(err) {
console.log (err) ;
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('an error occured', 'utf-8');
});
//send file
}
else{
console.log ('password wrong');
fs.readFile(__dirname +'/wrongpassword.html', function(error, content) {
if (error) {
res.writeHead(500);
res.end();
}
else {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(content, 'utf-8');
}
});
}
}); // req on end function end
}
}).listen(port, host);

Categories

Resources