formidable doesnt work with express - node.js

Before you wast any time : please note that this is a reference question , just in case some one needed it. but please feel free to correct me :)
so , im trying to use formidable (i know that it's so similar to bodyParser and that i should be using body parser instead ! ) with express . the problem that it doesnt work at all .
here is simple part of my code (relevant part )
form.on('progress', function (bytesReceived, bytesExpected) {
console.log(bytesExpected);
console.log('progress ');
if (bytesReceived > options.maxPostSize) {
console.log('bla ');
req.connection.destroy();
}
}).on('end', finish).parse(req,function(err, fields, files) {
console.log(files);
});
now if i try to console.log -> err , fields , or files it doesnt work .
an the only event that is being emitted is progress .

if you use app.use(express.bodyParser())
is equivalent to:
app.use(express.json());
app.use(express.urlencoded());
app.use(express.multipart());
the multipart use formidable, so events doesn't trigger,you can remove app.use(express.multipart()); then you can use formidable object.

The problem is caused by the parse function . To solve this you need to not use the bodyParser .
So let's assume that i have a route /files which only recives a post request then you need to disable the bodyParser just for that route like so :
app.use(function(req,res,next){
// important .. this will skip body parser to avoide issues with formidable
if((req.path == '/file' ||req.path == '/file/') &&req.method === 'POST'){
// GET , PUT , DELETE ,etc... will have bodyParser ^^^^^^^^^^^^^^^^^^^^^
return next();
}
express.bodyParser(req,res,next);
next();
});

Related

Node Js API : where the undefined comes from?

I write this code to get the array from url. this is the url : http://localhost:3000/main?a=aaa.jpg&a=bbb.jpg
And here is the code :
//Define module
var express = require('express');
var app = express();
const { exec } = require('child_process');
//extract function
function extract (req,res,next){
res.write(`filename : ${req.query.a}`); //kt page
console.log(req.query.a);//kt terminal
next();
};
//main function
function main (req,res,next){
res.write('\nkuor dok \n');
res.end();
};
app.use(extract);
app.get('/main',main);
app.listen(3000);
This is the output in terminal.
Array(2) ["aaa.jpg", "bbb.jpg"]
undefined
The question is where the undefined comes from? It affected everything i need to do. The array is perfectly fine. But suddenly undefined comes out. Can anyone help me. Thank you in advance.
I tried the code you provided above and i got only the array in the terminal
[ 'aaa.jpg', 'bbb.jpg' ]
When i tried the url in the browser i got
filename : aaa.jpg,bbb.jpg
kuor dok
as the output. i didn't get any undefined
I see that you are trying to define extract function as a middleware. It will be executed for every request
try to comment app.get:
app.use(extract);
//app.get('/main', main);
app.listen(3000);
Then try to make the request
GET: http://localhost:3000/main?a=aaa.jpg&a=bbb.jpg
you will get
[ 'aaa.jpg', 'bbb.jpg' ]
You are handling the request twice. First by the global middleware, the second time by app.get() that calls also the middleware extract before main
As I see app.get don't handle your query params and you got undefined due to an empty object try to log: req.query intead of req.query.q
function extract(req, res, next) {
res.write(`filename : ${req.query.a}`); //kt page
console.log(req.query); //kt terminal
next();
};

Express js optional parameter

I'm looking to add an optional parameter to an express route where var1 has to be set but var 2 can be ommited (/test/0 and /test/0/0 should both work).
I could create another rule, or juste evaluate the string "test/0/0" but I'm wondering if there is no other way.
app.get('/test/:var1/:var2', function(req, res){
// DO SOMETHING
});
Thanks !
app.get('/test/:var1/:var2*?',function(req,res)
{
if(!req.params.var2){
// do something when there is no optionalParam
}
res.json({ var: req.params.var1,
var2: req.params.var2 });
});
just call
http://127.0.0.1:8080/test/44
output
{"var":"44"}
incase of passing both
{"var":"44","var2":"77"}

Add All Routes in ./routes to Middleware Stack

Right now I am using app.use() and require() for each route in my routes directory to add them to the middleware stack (I am using Express).
app.use('/', require('./routes/index'));
app.use('/users', require('./routes/users'));
app.use('/post', require('./routes/post'));
app.use('/submitPost', require('./routes/submitPost'));
...
Instead of doing this manually for each file, I would like to use a for-loop to iterate through the route files in ./routes and add each file to the middleware stack. This is what I have, but it isn't working:
require('fs').readdir('/routes', function (err, files) {
if (!err) {
for (var i = 0; i < files.length; i++) {
var file = files[i].substr(files[i].lastIndexOf('.'));
app.use('/' + file, require('./routes/' + file));
}
}
});
Could someone help me correct this bit of code. On another note, are there any disadvantages to automatically adding all routes in ./routes to the middleware stack?
Thanks in advance.
The main issue here is probably when you are adding the middleware. You are using readdir - the asynchronous method. You likely have a catch-all 404 handler declared after your code, and as the routes you are requiring are added asynchronously, they will probably be added after the catch-all. When the request propagates through the middleware, this would terminate it before it even got to the route.
One other issue is the path you are using: /routes will attempt to look in the route of your filesystem. ./routes or __dirname + '/routes' is probaby what you want.
The following code sample works for me:
var files = require('fs').readdirSync('./routes')
for (var i = 0; i < files.length; i++) {
var file = files[i].substr(0, files[i].lastIndexOf('.'));
app.use('/' + file, require('./routes/' + file));
}
By the way, you can use file-manifest for this. It was actually created specifically for this use case, although it still expects you to call app.use yourself, since order matters for express routes.
So you can do something like:
var fm = require('file-manifest');
var routes = fm.generate('./routes');
app.use('/', routes.home);
app.use('/foo', routes.foo);
// etc.
If you really want it to all happen magically, you could make that work with a custom reduce function, but this is much more explicit and ensures that routes are set up in the right order (so you don't end up with /foo falling before /foo/bar and preventing it from being reached).
I believe I am supposed to qualify that I wrote this library.
There are a few ways to do this. Here's a clean implentation using the basic fs and path modules.
var fs = require("fs"),
path = require("path");
var root = "./routes/"
fs.readdir(root, function (err, files) {
if (err) {
throw err;
}
files.forEach(function (file) {
var filename = file.slice(0, -3);
var routePath = '/' + ((filename === 'index') ? '' : filename); //filter index to use just '/'
app.use(routepath, require(root + filename));
});
});

How to get list of all routes I am using in restify server

I have a app designed as follows;
//server.js =====================================================
var restify = require('restify'),
route1 = require('./routes/route1),
route2 = require('./routes/route2),
....
....
....
var server = restify.createServer({
name: 'xyz_server'
});
route1(server);
route2(server);
Now each route file looks like belwo
//route1.js =====================================================
module.exports = function(server) {
server.get('/someRoute',function(req,res,next){
//.. do something
});
server.get('/anotherRoute',function(req,res,next){
//..something else
});
};
Now the issue is tht we have dozen's of route files and hundreds of routes in total.
There are multiple developers working on this project and several routes are being added daily.
Is there a function in restify gives me a list of all routes in the system ?
What i am looking for is something like:
server.listAllRoutes();
Is anyone aware of this ?
Try something like this
function listAllRoutes(server){
console.log('GET paths:');
server.router.routes.GET.forEach(
function(value){console.log(value.spec.path);}
);
console.log('PUT paths:');
server.router.routes.PUT.forEach(
function(value){console.log(value.spec.path);}
);
}
listAllRoutes(server);
This should list all GET and PUT paths, adding POST and DELETE should be easy :)
2019 update: server.router.routes is no longer available instead we have server.router.getRoutes() which returns a Map. So we can log all the routes using:
function listAllRoutes(server) {
Object.values(server.router.getRoutes()).forEach(value =>
console.log(
`ENDPOINT REGISTERED :: ${value.method} :: ${server.url}${value.path}`
)
);
}
http://restify.com/docs/server-api/#server
There is a router.getRoutes() method, but it returns an object which is not the best to work with for listing things. You could fiddle around with that to turn it into an array with the shape that you like.
Alternatively, you can access all the routes as an array and then map them, even better if you use a lib like better-console to give you console.table in node. The following is working nicely for me in restify#8.3.0:
import console from 'better-console';
function listRoutes(server) {
const { routes } = server.router._registry._findMyWay; // beware these are probably meant to be private APIs, they could be subject to change
const mapped = routes.map(({ method, path }) => ({ method, path }));
console.table(mapped.sort((a, b) => a.method > b.method));
}

Node.js leaking path info, how to solve it?

I have a webserver running... and if I curl from another server. Something like that:
curl http://myserver.com/../../../../../etc/rsyslog.conf
then I can see the server info.
Is that a known problem?
UPDATE
here is my server code:
app = express.createServer(
gzip.staticGzip(__dirname + '/public', {maxAge:5000 }),
express.cookieParser(),
express.bodyParser()
);
got a fix like that:
var urlSecurity = function () {
return function (req, res, next) {
if (req.url.indexOf('../') >=0) {
res.send('<div>Server Error</div>' , 500);
} else if (req.url.indexOf('/..') >=0) {
res.send('<div>Server Error</div>' , 500);
} else {
next();
}
}
}
app = express.createServer(
urlSecurity (),
gzip.staticGzip(__dirname + '/public', {maxAge:5000 }),
express.cookieParser(),
express.bodyParser()
);
is this good enough?
You have a serious security flaw in your program. Fix it immediately.
My best guess from the presented symptom is that you're doing something like:
http.createServer(function (request, response) {
var file = path.resolve('/path/to/files', request.url)
fs.createReadStream(file).pipe(response)
})
This is extremely unwise! Always sanitize user input. In this case, it's quite easy:
http.createServer(function (request, response) {
var requestedFile = path.join('/', request.url);
var file = path.join('/path/to/files', requestedFile)
fs.createReadStream(file).pipe(response)
})
So, first we path.join the requested url onto '/'. This will et rid of any .. shenanigans, making it more sanitary. Then, we path.join that onto our url.
Why use path.join rather than path.resolve in this case? Because path.join just joins path parts, rather than resolving them, so a leading / won't have any ill effects.
After the immediate fix, I have done a lot of testing. and I confirm the following:
It is NOT a node problem primarily. It is the gzippo module causing the problem. Gzippo 0.1.3 is causing that problem. 0.1.4 has no problem. NOt sure why is like that. but better not to use the older version of gzippo.
The simplest solution is insecureFileName.split('/').pop() will always returns only fileName.
'index.html'.split('/').pop() => 'index.html'
'../../../index.html'.split('/').pop() => 'index.html'
I sanitize user filenames with:
path.basename(filename);
e.g.:
const path = require('path');
let filename = '../../../../../../../etc/passwd';
filename = path.basename(filename); // 'passwd'
let pathToFile = path.join('/path/from/config/to', filename);
console.log(pathToFile); // 'path/from/config/to/passwd'

Resources