Invoking an asynchronous method inside a middleware in node-http-proxy
Asked Answered
L

2

7

I'm trying to create a proxy with node-http-proxy in Node.js that checks whether a request is authorized in a mongodb.

Basically, I created a middleware module for the node-http-proxy that I use like this:

httpProxy.createServer(
require('./example-middleware')(),
9005, 'localhost'
).listen(8005)

What the middleware module does is using mongojs to connect to mongodb and run a query to see if the user is authorized to access the resource:

module.exports = function(){
// Do something when first loaded!
console.log("Middleware loaded!");

return function (req, res, next) {
var record = extractCredentials(req);
var query = -- Db query --

//Debug:
log("Query result", query);

db.authList.find(query).sort({
    "url.len": -1
}, function(err, docs){
    console.log(docs);

    // Return the creator for the longest matching path:
    if(docs.length > 0) {
        console.log("User confirmed!");
        next();
    } else {
        console.log("User not confirmed!");
        res.writeHead(403, {
            'Content-Type': 'text/plain'
        });
        res.write('You are not allowed to access this resource...');
        res.end();
    }

});

}
}

Now the problem is that as soon as I add the asynchronous call to mongodb using mongojs the proxy hangs and never send the response back.

To clarify: on a "User not confirmed" everything works fine and the 403 is returned. On a "user confirmed" however I see the log but the browser then hangs forever and the request isn't proxied.

Now, if I remove the "user confirmed" and next() part outside of a callback it does work:

module.exports = function(){
// Do something when first loaded!
console.log("Middleware loaded!");

return function (req, res, next) {
    var record = extractCredentials(req);
    var query = --- query ---


    console.log("User confirmed!");
    next();
}

but I can't do that since the mongojs query is meant (rightfully I guess) to be executed asynchronously, the callback being triggered only when the db replied...

I also tried the version without using a middleware:

http.createServer(function (req, res) {
  // run the async query here!
  proxy.proxyRequest(req, res, {
  host: 'localhost',
  port: 9000
});
}).listen(8001);

But that did not help either...

Any clue? Note that I'm new to node.js so I suspect a misunderstanding on my side...

Lenorelenox answered 26/7, 2012 at 15:4 Comment(1)
what middleware are you using? connect?Dillon
L
6

Found the answer, actually the catch is that the request needs to be buffered:

httpProxy.createServer(function (req, res, proxy) {
// ignore favicon
if (req.url === '/favicon.ico') {
    res.writeHead(200, {
        'Content-Type': 'image/x-icon'
    } );
    res.end();
    console.log('favicon requested');
    return;
}

var credentials = extractCredentials(req);
console.log(credentials);

var buffer = httpProxy.buffer(req);

checkRequest(credentials, function(user){
    if(user == ...) {
        console.log("Access granted!");
        proxy.proxyRequest(req, res, {
            host: 'localhost',
            port: 9005, 
            buffer: buffer
        });
    } else {
        console.log("Access denied!");
        res.writeHead(403, {
            "Content-Type": "text/plain"
        });
        res.write("You are not allowed to access this resource...");
        res.end();
    }

});

}).listen(8005);
Lenorelenox answered 30/7, 2012 at 10:48 Comment(1)
But how would you that inside a middleware, as the proxy object it's still not available (because middlewares are loaded before you declare the function containing the "proxy" argument) ?Englacial
C
2

Two problems:

  1. You're not calling next(); in the else case of your sort callback.
  2. The second parameter to your sort callback is a Cursor, not an array of documents. As such, docs.length > 0 is never true and the code always follows the else path.
Cyprio answered 26/7, 2012 at 15:48 Comment(3)
Hi! Thanks. I guess my question wasn't clear enough so I edited it (my bad!). I did call write a response in the else clause (see new edits) and the second param of sort is a callback not a cursor, as said I am using mongojs not the native mongo javascript driver (the query works fine).Lenorelenox
Ah, no problem; my bad for missing the proxy part of this. Isn't the third parameter to your node-http-proxy middleware function a proxy object, not a next function? github.com/nodejitsu/node-http-proxy/…Cyprio
Well apparently it is a next() function. I tried with a proxy but it yelds the same result: both proxy.proxyRequest(req, res); and next(); work when outside of a callback, but not inside. The proxy still hangs...Lenorelenox

© 2022 - 2024 — McMap. All rights reserved.