Change the name of uploaded file in node.js - node.js

I am using node.js to upload a file. But it uploads the file in the /tmp folder with a random like name (such as: 132d439bb31ee13daaf6ce02e223738f). I want the node to upload the file in a given directory with a given name. How can I make it? here is my code:
var http = require("http"),
url = require("url"),
sys = require("sys"),
events = require("events"),
fs = require("fs"),
formidable = require('formidable'),
util = require('util');
var server = http.createServer(function(req, res) {
switch (url.parse(req.url).pathname) {
case '/':
display_form(req, res);
break;
case '/upload':
upload_file(req,res);
break;
default:
show_404(req, res);
break;
}
});
server.listen(8124);
function display_form(req, res) {
//displays an html form with an upload and a submit button
}
function upload_file(req, res) {
if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
// Instantiate a new formidable form for processing.
var form = new formidable.IncomingForm();
// form.parse analyzes the incoming stream data, picking apart the different fields and files for you.
form.parse(req, function(err, fields, files) {
if (err) {
// Check for and handle any errors here.
console.error(err.message);
return;
}
form.on('fileBegin', function(name, files) {
files.name="./guake.up";
});
res.writeHead(200, {'content-type': 'text/plain'});
res.write('received upload:\n\n');
console.log(files.name);
// This last line responds to the form submission with a list of the parsed data and files.
res.end(util.inspect({fields: fields, files: files}));
});
return;
}
}
function show_404(req, res) {
//shows a 404 page
}

I found the answer and I only need to add the following code before my form.parse method:
form.on('error', function(err) {
throw err;
})
/* this is where the renaming happens */
.on ('fileBegin', function(name, file){
//rename the incoming file to the file's name
file.path = form.uploadDir + file.name;
});
and the problem is solved

Related

Requesting file directly with Node JS server returns with nothing

So I am trying to get a node js server to serve a file. Even when I call the file directly in the url (http://localhost:8080/media/file.mp3) it returns no data. When I console.log on the write statement, it returns false, meaning that some or all the of the data isn't being flushed out and sent to the client.
The code:
http.createServer(function(req, res){
res.on('end',()<= {
if (req.url.includes("media")){
res.setHeader('Content-Type','audio/mp3');
res.setHeader('Retry-After', '1');
res.setHeader('method','POST');
res.setHeader('Connection','keep-alive');
res.writeHead(200,{'Content-Type':'audio/mp3'});
console.log("/path_to_file_from_root_to_index"+req.url);
fs.readFile("/path_to_file_from_root_to_index"+req.url,function(err,data){
if (err){
console.log(err);
} else {
res.write(data);
res.end();
}
});
}).listen(8080);
What is being shown in the browser when req.url='/media/file.mp3':
var fs = require('fs'),
http = require('http'),
path = require('path');
http.createServer(function(req, res) {
if (req.url.includes('media')) {
res.writeHead(200, {
'Content-Type': 'audio/mp3'
});
console.log(path.join(__dirname, '/path_to_file_from_root_to_index' + req.url));
fs.readFile(path.join(__dirname, '/path_to_file_from_root_to_index' + req.url), function(err, data) {
if (err) {
console.log(err);
} else {
res.end(data);
}
});
}
}).listen(8080);

Parse form value with formidable to filename

I´m using formidable to handle my file uploads in NodeJs. I´m a little stuck at parsing field values.
How do I get the value of project_id to the form handler, so I can write the parameter in my filename?
<input type="text" id="project_id" value="{{projects._id}}" readonly>
EDIT
To be more specific, here´s a detailed view of my form-upload handling:
app.post('/uploads/', function (req, res){
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
res.writeHead(200, {'content-type': 'image/jpeg'});
res.write('received upload: \n\n');
var project = fields.project_id;
res.end(util.inspect(project, {fields: fields, files: files}));
});
form.on('end', function(project, fields, files){
console.log(project);
/*Temporary location of our uploaded file */
var temp_path = this.openedFiles[0].path;
/*The file name of the uploaded file */
var file_name = project + '.' + this.openedFiles[0].name;
I can log the var project in the form.parse part. But I don´t get the variable in the form.on('end'... part.
HTML form
<form id="uploadForm"
enctype="multipart/form-data"
action="/uploads/"
method="post">
<input type="text" name="project_id" id="project_id" value="{{projects._id}}" readonly>
<input multiple="multiple" type="file" name="upload" />
<button type="submit">Upload</button>
</form>
Formidable's end callback doesn't take any parameters, but I'm not sure you even need to call it if you're using the parse callback. I think what you're looking for is something like this:
var fs = require('fs');
app.post('/uploads', function(req, res, next) {
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
if (err) next(err);
// TODO: make sure my_file and project_id exist
fs.rename(files.my_file.path, fields.project_id, function(err) {
if (err) next(err);
res.end();
});
});
});
You would need to listen for the end() event if you chose not to use the parse callback, like this:
new formidable.IncomingForm().parse(req)
.on('file', function(name, file) {
console.log('Got file:', name);
})
.on('field', function(name, field) {
console.log('Got a field:', name);
})
.on('error', function(err) {
next(err);
})
.on('end', function() {
res.end();
});
Client side script:
//Upload the file
var fd = new FormData();
//Take the first selected file
fd.append("dbDocPath", 'invoices/' + file.name);
fd.append("file", file);
$http({
method: 'POST',
url: $rootScope.apiUrl + 'uploadDocToServer',
data: fd,
headers: {
'Content-Type': undefined
},
//prevents serializing payload. don't do it.
transformRequest: angular.identity,
}).success(function (response) {
if (response.success) {
}
})
Server side script:
var fileDir = path.join(__dirname, '/../uploads');
// create an incoming form object
var form = new formidable.IncomingForm();
var dbDocPath = '';
form.parse(req)
.on('field', function (name, field) {
//console.log('Got a field:', field);
//console.log('Got a field name:', name);
dbDocPath = field;
})
.on('file', function (name, file) {
//console.log('Got file:', name);
// specify that we want to allow the user to upload multiple files in a single request
//form.multiples = true;
// store all uploads in the /uploads directory
form.uploadDir = fileDir;
fs.rename(file.path, path.join(form.uploadDir, file.name));
// every time a file has been uploaded successfully,
// rename it to it's orignal name
var bucket = new AWS.S3();
//console.log(dbDocPath);
var params = {
Bucket: DocsConfig.bucketName,
Key: dbDocPath,
Body: fs.createReadStream(path.join(form.uploadDir, file.name)),
ACL: 'public-read'
};
bucket.putObject(params, function (perr, pres) {
if (perr) {
//console.log("Error uploading data: ", perr);
} else {
fs.unlinkSync(path.join(form.uploadDir, file.name));
//console.log("Successfully uploaded data", pres);
}
});
})
.on('error', function (err) {
res.send({'success': false, error: err});
})
.on('end', function () {
res.send({'success': true});
});
// parse the incoming request containing the form data
//form.parse(req);
Just keep one thing in mind that the sequence of sending parameters to formData() should be same as mentioned in above code as file upload needs path to upload to the destiny.

Serving css, js files in Node.js without frameworks like Express

This question has probably been asked earlier but the answers are not very convincing.
I have the following code with me -
var http = require('http'),
fs = require('fs');
connect = require('connect');
function serveStaticFile(res, path, contentType, responseCode) {
if(!responseCode) responseCode = 200;
fs.readFile(__dirname + path, function(err,data) {
if(err) {
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end('500 - Internal Error');
} else {
res.writeHeader(responseCode,
{ 'Content-Type': contentType });
res.write(data)
res.end();
}
});
}
http.createServer(function(req,res){
// normalize url by removing querystring, optional
// trailing slash, and making lowercase
var path = req.url.replace(/\/?(?:\?.*)?$/, '')
.toLowerCase();
switch(path) {
case '': serveStaticFile(res, '/public/index.html','texthtml');
break;
default:
serveStaticFile(res, '/public/404.html', 'text/html',
404);
break;
}
}).listen(3000);
console.log('Server started on localhost:3000; press Ctrl-C to terminate....');
I am just not able to load the css and js files mentioned in the index.js. What am I doing wrong? If I open index.js in the browser directly, the css and js load fine.
Express uses serve-static for serving static directories which is uses send for streaming files. You can use that instead of express, or take at a look their implementation.
What are you think about send ? Use that like this:
function serveStaticFile(res, path, contentType, responseCode) {
if(!responseCode) responseCode = 200;
res.status = responseCode;
function error(err) {
res.statusCode = err.status || 500;
res.end(err.message);
}
function headers(res, path, stat) {
res.setHeader('Content-type', contentType);
}
send(req, path, {root: __dirname})
.on('error', error)
.on('headers', headers)
.pipe(res);
}

NodeJS - Stream video that is being downloaded

I am writing a program that will stream a video file that is currently being downloaded onto the drive. The problem I am having seems to be getting the browser to actually play the video. the script listens for file changes, and then streams the rest, but the browser doesnt do anything besides display a blank Video page.
var fs = require('fs'),
http = require('http'),
filename = '/home/qrpike/Videos/topgears.mp4';
http.createServer(function (req, res) {
console.log(req.url);
if( req.url == '/video.mp4'){
res.writeHead(200,{
'Content-Type' : 'video/mp4',
'Cache-Control' : 'public',
'Connection' : 'keep-alive',
'Content-Disposition' : 'inline; filename=topgears.mp4;',
'Content-Transfer-Encoding' : 'binary',
'Transfer-Encoding' : 'chunked'
});
fs.open(filename, 'r', function(err, fd) {
if (err) throw new Error('Could not open file');
var position = 0;
fs.stat(filename, read);
fs.watchFile(filename, read.bind(null, null));
function read(err, stat) {
var delta = stat.size - position;
if (delta <= 0) return;
fs.read(fd, new Buffer(delta), 0, delta, position, function(err, bytes, buffer) {
console.log("err", err, "bytes", bytes, "position",position,"delta",delta);
res.write(buffer.toString('binary'));
});
position = stat.size;
}
});
}
}).listen(1337);
console.log('Server running at http://127.0.0.1:1337/');
So this answer depends on growing-file, which in theory does what you want. My concern is that the project hasn't had a commit in two years so I have no idea if it still works. That being said, this worked for me locally (though I didn't test piping to the video file):
var fs = require('fs');
var http = require('http');
var GrowingFile = require('growing-file');
var FILENAME = '/home/dave/Desktop/video/video.ogg';
var server = http.createServer(function(req, res) {
var file;
if (req.url === '/video.ogg') {
res.writeHead(200, {
'Content-Type': 'video/ogg'
});
file = GrowingFile.open(FILENAME);
file.pipe(res);
} else {
res.statusCode = 404;
res.end('Not Found');
}
});
server.listen(1337);

Empty HTTP response

For some reason, this code keeps failing :
var http = require('http');
var url = require ('url');
var jade = require('jade');
var fs = require('fs');
http.createServer(function(req, res) {
// Request handlers
var path = url.parse(req.url, true).pathname;
var dot = path.lastIndexOf('.');
var extension = path.substr(dot + 1);
// Response handlers
switch(extension) {
case 'css' :
res.writeHeader(200, {"Content-Type": "text/css"});
fs.readFile(path.substr(1, dot - 1) + '.css', function (err, css) {
if(err) {
res.write(err, 'utf8')
};
res.write(css, 'utf8')
});
break;
case 'js' :
res.writeHeader(200, {"Content-Type": "text/javascript"});
fs.readFile(path.substr(1, dot - 1) + '.js', function (err, js) {
if(err) {
res.write(err, 'utf8')
};
res.write(js, 'utf8')
});
break;
default :
res.writeHeader(200, {"Content-Type": "text/html"});
jade.renderFile(path.substr(1, path.length) + '.jade', { title: 'test' }, function(err, html) {
if(err) {
res.write(err, 'utf8')
};
res.write(html, 'utf8');
});
break;
}
res.end();
}).listen(8080);
I don't get any errors, it's just that the responses seem to be empty.
There is a header but no css or javascript file.
The way I link them in Jade is the following :
link(rel='stylesheet', href='/css/bootstrap.min.css')
link(rel='stylesheet', href='/css/style.css')
Thank you in advance !
You've called res.end() too soon. Instead, put it after the last res.write() in each of your fs.readFile handlers.

Resources