There are many question similar to my question on stack overflow. However not solved my problem.
I am getting this error on Ubuntu 18.04:
Error: EXDEV: cross-device link not permitted, rename
'/tmp/upload_df97d265c452c510805679f968bb4c17' -> '/home/haider/workspaceNode/DSC_0076.JPG'
I Tried This code
var http = require('http');
var formidable = require('formidable');
var fs = require('fs');
http.createServer(function (req, res) {
if (req.url == '/fileupload') {
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
var oldpath = files.filetoupload.path;
var newpath = '/home/haider/workspaceNode/' + files.filetoupload.name;
fs.rename(oldpath, newpath, function (err) {
if (err) throw err;
res.write('File uploaded and moved!');
res.end();
});
});
} else {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<form action="fileupload" method="post" enctype="multipart/form-data">');
res.write('<input type="file" name="filetoupload"><br>');
res.write('<input type="submit">');
res.write('</form>');
return res.end();
}
}).listen(8081);
I suppose that Node's fs.rename cannot rename across filesystems (that is, limited to link/unlink within one filesystem).
Wherever your /home is, it's a safe bet to suppose that /tmp is a tmpfs filesystem actually residing in memory. (You can check in the output of mount.)
So, to move a file, you have to fs.copyFile your data to the destination, then fs.unlink the original downloaded file.
You can upload a temporary file into a device with script's file system:
var form = new formidable.IncomingForm({
uploadDir: __dirname + '/tmp', // don't forget the __dirname here
keepExtensions: true
});
from here https://stackoverflow.com/a/14061432/7773566
Related
I am trying to get a file from html form and store it in another folder. It's basically cloud function, and I am new to both node.js and firebase so don't know what I am doing wrong. What I manage to do is:
const fileMiddleware = require('express-multipart-file-parser');
app.post("/sendMail", (req, res) => {
const {
fieldname,
filename,
encoding,
mimetype,
buffer,
} = req.files[0];
console.log(req.files[0].originalname);
var fs = require('fs')
var oldPath = req.files[0].originalname;
var newPath = '/functions/'+oldPath;
fs.rename(oldPath, newPath, function (err) {
if (err) throw err
console.log('Successfully renamed - AKA moved!')
});
});
Whenever I try to move file, I got path issues. The error is as follows:
[Error: ENOENT: no such file or directory, rename 'C:\Users\Maisum Abbas\now\functions\sendMail.txt'
> 'C:\functions\sendMail.txt'] {
> errno: -4058,
> code: 'ENOENT',
> syscall: 'rename',
> path: 'C:\\Users\\Maisum Abbas\\now\\functions\\sendMail.txt',
> dest: 'C:\\functions\\sendMail.txt'
> }
Also, this is the path where I want to actually move the file but oldpath is already setup like this.
C:\Users\Maisum Abbas\now\functions\sendMail.txt
Since I needed to attach a file with email, it was causing path issues. I tried it with multer and it works. What I did:
//call libraries here
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, 'resume/');
},
filename: function (req, file, callback) {
callback(null, file.fieldname + '-' + Date.now());
}
});
var upload = multer({ storage : storage}).single('filetoupload');
app.post("/careerMail", (req, res) => {
const { name } = req.body;
const { email } = req.body;
const { phone } = req.body;
upload(req,res,function(err) {
if(err) {
return res.end("Error uploading file.");
}
});
const dest = 'mymail';
const mailOptions = {
from: email, // Something like: Jane Doe <janedoe#gmail.com>
to: dest,
subject: 'Candidate Application', // email subject
html: `<div>
<strong>From:</strong> ` +
name +
`<br /><br />
<strong>Email:</strong> ` +
email +
`<br /><br />
<strong>Phone:</strong> ` +
phone +
`<br /><br />
</div>
`,// email content in HTML
attachments: [
{
filename: req.files[0].originalname,
content: req.files[0].buffer.toString("base64"),
encoding: "base64"
}
]
and rest of the code...
I suggest rethinking this approach altogether. You won't be able to move files around in a deployed function. The nodejs runtime filesystem doesn't allow any files to be written anywhere in the filesystem, except for os.tmpdir() (which is /tmp on Linux).
If you need to write a file temporarily, you should definitely only use that tmp space. Be aware that files written there occupy memory and should be deleted before the function terminates, or you could leak memory.
You can read files that you deployed with your code, but you should do that through relative paths.
I ran into same problem while moving file. I sort this problem by using a function to get the application root folder and then concatenate rest of the location.
//place this file on application root.
//import where you need to get the root path.
const path = require('path');
module.exports = (function(){
return path.dirname(require.main.filename || process.mainModule.filename);
})();
//taking your case move location.
const rootPath = //require the above module.
const newPath = rootPath + /functions/' +oldPath;
fs.rename(oldPath, newPath, function (err) {
if (err) throw err
console.log('Successfully renamed - AKA moved!')
});
I am trying to upload some files, through an HTML form, in my local drive, which I was able to complete successfully. However, when attempting to play the mp3 uploaded file, by accessing the url of the "mp3 player", the server redirects me to the uploading page and I can not understand why this happens. I am quite a begginer, when it comes to node.js and I do not really know that much about JavaScript, as I have little experience with it. You can check the code below:
var http = require('http'),
fs = require('fs'),
filePath = './test.mp3',
stat = fs.statSync(filePath);
var formidable = require('formidable');
http.createServer(function(request, response) {
//fs.createReadStream(filePath).pipe(response);
if(request.url == '/playUploadedFile') {
fs.createReadStream(filePath).pipe(response);
response.writeHead(200, {
'Content-Type': 'audio/mpeg',
'Content-Length': stat.size,
});
}
if (request.url == '/fileupload') {
var form = new formidable.IncomingForm();
form.parse(request, function (err, fields, files) {
var oldpath = files.filetoupload.path;
var newpath = __dirname + '/' + files.filetoupload.name;
filePath = newpath;
console.log(filePath);
fs.rename(oldpath, newpath, function (err) {
if (err) throw err;
response.write('File uploaded and moved!');
//request.url = '/playUploadedFile';
response.end();
});
});
} else {
response.writeHead(200, {'Content-Type': 'text/html'});
response.write('<form action="fileupload" method="post" enctype="multipart/form-data">');
response.write('<input type="file" name="filetoupload"><br>');
response.write('<input type="submit">');
response.write('</form>');
return response.end();
}
}).listen(8080)
In order to serve static file you have to declare your upload path to static. This way node understands the files within the specified path needs to be served exactly the way it is. The easiest way to do this is to use express https://expressjs.com/en/starter/static-files.html. But you can also use node-static https://www.npmjs.com/package/node-static package as well.
I am trying to download and later serve images using Node.js. I need to save each image in a directory specified by the url. My code for downloading images gets stuck because there is no directory to save them to. I am trying to create one using mkdirp but keep getting the error [Error: EACCES: permission denied, mkdir '/20110'] errno: -13, code: 'EACCES', syscall: 'mkdir', path: '/20110'. Here is my full code:
controller.serveImages = function(req, res, connection) {
var file = "/" + req.params.attachmentId + "/" + req.params.attachmentFileName;
console.log("serve called", file);
var fs = require('fs'),
request = require('request');
var mkdirp = require('mkdirp');
mkdirp( "/" + req.params.attachmentId, function (err) {
if (err) console.error(err)
else console.log('Directory made!')
});
fs.readFile(file, function(error, data) {
console.log("reading");
if(error){
if (error.code === 'ENOENT') { //File not downloaded
var download = function(uri, filename, callback){
request.head(uri, function(err, res, body){
console.log('content-type:', res.headers['content-type']);
console.log('content-length:', res.headers['content-length']);
request(uri).pipe(fs.createWriteStream(filename)).on('close', callback);
});
};
download('https://www.google.com/images/srpr/logo3w.png', file, function(){
console.log('done');
});
}
else{
console.log(error)
}
}
else{
console.log("Found locally", data, file);
res.sendFile(file);
}
});
};
The code is adapted from here. An example request would be /20110/TNCA+PB.png. With that I would want to create a directory /20110 and save TNCA+PB.png there.
Seems that you're trying to create the folder at File System root level. Have you tried to create the folder under the application folder instead? Writing to root level is never a good idea.
Here are some suggestions to get the app running path Determine project root from a running node.js application , then you can append that to your mkdirp function.
Regards
I'm trying to generate a url using nodeJS that points to a static resource, which is a JS file. It throws me a 404 error, Not Found.
First I start the node server with node index.js
The node.js file has this:
var fs = require('fs');
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.writeHead(responseCode,
{'Content-Type': 'text/plain'});
res.end(data);
}
});
}
http.createServer(function(req,res){
var path = req.url.toLowerCase();
switch(path) {
case '/avisarPagoAhora':
serveStaticFile(res, '/avisoPago/avisos-de-pago.html', 'text/html');
break;
default:
res.writeHead(404,{'Content-Type': 'text/plain'});
res.end('Not Found');
break;
}
}).listen(3000);
console.log('Server started on localhost:3000; press Ctrl-C to terminate...');
Now, I've got index.js inside var/www/html/avisoPago
And my avisos-de-pago.html file is inside the avisoPago folder that's inside avisoPago.
So the path to index.js is: var/www/html/avisoPago/index.js
And the path to avisos-de-pago.html file is: var/www/html/avisoPago/avisoPago/avisos-de-pago.html
What Am I doing wong that it doesn't find the file when I type http://myDomain:3000/avisarPagoAhora
var path = req.url.toLowerCase(); The "toLowerCase" function makes the "avisarPagoAhora" turn into "avisarpagoahora" and because of it node can't find the right path '/avisarPagoAhora'. Try to remove the toLowerCase function or make the case statement "case '/avisarpagoahora':"
I am trying to setup a file API in my node.js application. My goal is to be able to write the file stream directly to gridfs, without needing to store the file to disk initially. It seems like my create code is working. I am able to save a file upload to gridfs. The problem is reading the file. When I try to download a saved file via a web browser window, I see that the file contents are wrapped with something like the following:
------WebKitFormBoundarye38W9pfG1wiA100l
Content-Disposition: form-data; name="file"; filename="myfile.txt"
Content-Type: text/javascript
***File contents here***
------WebKitFormBoundarye38W9pfG1wiA100l--
So my question is what do I need to do to strip the boundary information from the file stream before saving it to gridfs? Here's the code i'm working with:
'use strict';
var mongoose = require('mongoose');
var _ = require('lodash');
var Grid = require('gridfs-stream');
Grid.mongo = mongoose.mongo;
var gfs = new Grid(mongoose.connection.db);
// I think this works. I see the file record in fs.files
exports.create = function(req, res) {
var fileId = new mongoose.Types.ObjectId();
var writeStream = gfs.createWriteStream({
_id: fileId,
filename: req.query.name,
mode: 'w',
content_type: req.query.type,
metadata: {
uploadedBy: req.user._id,
}
});
writeStream.on('finish', function() {
return res.status(200).send({
message: fileId.toString()
});
});
req.pipe(writeStream);
};
// File data is returned, but it's wrapped with
// WebKitFormBoundary and has headers.
exports.read = function(req, res) {
gfs.findOne({ _id: req.params.id }, function (err, file) {
if (err) return res.status(400).send(err);
// With this commented out, my browser will prompt
// me to download the raw file where I can see the
// webkit boundary and request headers
//res.writeHead(200, { 'Content-Type': file.contentType });
var readstream = gfs.createReadStream({
_id: req.params.id
// I also tried this way:
//_id: file._id
});
readstream.pipe(res);
});
};
By the way, i'm not currently using any middleware for these routes, but am open to doing so. I just didn't want the file to hit the disk prior to being sent to gridfs.
Edit:
Per #fardjad, I added the node-multiparty module for multipart/form-data parsing and it kind of worked. But when I download an uploaded file and compare with an original (as text), there are lots of differences in the encoding, and the downloaded file won't open. Here's my latest attempt.
'use strict';
var mongoose = require('mongoose');
var _ = require('lodash');
var multiparty = require('multiparty');
var Grid = require('gridfs-stream');
Grid.mongo = mongoose.mongo;
var gfs = new Grid(mongoose.connection.db);
exports.create = function(req, res) {
var form = new multiparty.Form();
var fileId = new mongoose.Types.ObjectId();
form.on('error', function(err) {
console.log('Error parsing form: ' + err.stack);
});
form.on('part', function(part) {
if (part.filename) {
var writeStream = gfs.createWriteStream({
_id: fileId,
filename: part.filename,
mode: 'w',
content_type: part.headers['content-type'],
metadata: {
uploadedBy: req.user._id,
}
})
part.pipe(writeStream);
}
});
// Close emitted after form parsed
form.on('close', function() {
return res.status(200).send({
message: fileId.toString()
});
});
// Parse req
form.parse(req);
};
exports.read = function(req, res) {
gfs.findOne({ _id: req.params.id }, function (err, file) {
if (err) return res.status(400).send(err);
res.writeHead(200, { 'Content-Type': file.contentType });
var readstream = gfs.createReadStream({
_id: req.params.id
});
readstream.pipe(res);
});
};
Final Edit:
Here's a simple implementation that I copied from another developer and modified. This is working for me: (I'm still trying to figure out why it won't work in my original express app. Something seems to be interfering)
https://gist.github.com/pos1tron/094ac862c9d116096572
var Busboy = require('busboy'); // 0.2.9
var express = require('express'); // 4.12.3
var mongo = require('mongodb'); // 2.0.31
var Grid = require('gridfs-stream'); // 1.1.1"
var app = express();
var server = app.listen(9002);
var db = new mongo.Db('test', new mongo.Server('127.0.0.1', 27017));
var gfs;
db.open(function(err, db) {
if (err) throw err;
gfs = Grid(db, mongo);
});
app.post('/file', function(req, res) {
var busboy = new Busboy({ headers : req.headers });
var fileId = new mongo.ObjectId();
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
console.log('got file', filename, mimetype, encoding);
var writeStream = gfs.createWriteStream({
_id: fileId,
filename: filename,
mode: 'w',
content_type: mimetype,
});
file.pipe(writeStream);
}).on('finish', function() {
// show a link to the uploaded file
res.writeHead(200, {'content-type': 'text/html'});
res.end('download file');
});
req.pipe(busboy);
});
app.get('/', function(req, res) {
// show a file upload form
res.writeHead(200, {'content-type': 'text/html'});
res.end(
'<form action="/file" enctype="multipart/form-data" method="post">'+
'<input type="file" name="file"><br>'+
'<input type="submit" value="Upload">'+
'</form>'
);
});
app.get('/file/:id', function(req, res) {
gfs.findOne({ _id: req.params.id }, function (err, file) {
if (err) return res.status(400).send(err);
if (!file) return res.status(404).send('');
res.set('Content-Type', file.contentType);
res.set('Content-Disposition', 'attachment; filename="' + file.filename + '"');
var readstream = gfs.createReadStream({
_id: file._id
});
readstream.on("error", function(err) {
console.log("Got error while processing stream " + err.message);
res.end();
});
readstream.pipe(res);
});
});
See my comment on the issue you created on github. I had the same problem but I managed to debug the issue. I narrowed it down to where i was confident that the problem was a piece of express middleware modified the request. I disabled my middleware one by one until i found the unlikely culprit: connect-livereload
I commented out app.use(require('connect-livereload')()); and the problem went away.
I believe it was injecting the livereload script into the response (a binary image file).
Looks like the file has been uploaded through an HTML form, in that case you need to decode the multipart/form-data encoded data, re-assemble the parts if needed and save the file to GridFS. For parsing, you can use something like node-multiparty.