views:

58

answers:

1

I want to get request (POST) body from http.ServerRequest, but do so not straight when my request function is called, but only after some time (Redis query).

I have a very simple example to illustrate:

var http = require('http'),
    sys = require('sys');

http.createServer(function (req, res) {
    sys.puts("Got request");
    req.pause();
    setTimeout(function() { // In real code I'm accessing Redis here.
        var body = "";
        req.addListener('data', function (chunk) {
            sys.puts("Got 'data' event");
            body += chunk;
        });
        req.addListener('end', function () {
            sys.puts("Got 'end' event");
            res.writeHead(200, {'Content-Type': 'text/plain'});
            res.end(body);
        });
        req.resume();
    }, 10);
}).listen(8000);

In this example data and end events are completely missed, even though I'm calling req.pause()/req.resume(), so request's "stuck".

If I comment out setTimeout() call and do everything straight in request function, everything works as expected. But I want to query Redis to see whenever the request's valid. The POSTs are big file uploads, and I don't want to waste time waiting for unsuccessful upload to complete.

The simple way to do this is to delay the POST for some milliseconds (in my case POSTs would take at least several seconds, so such tiny delay is quite insignificant). The neater one is to start parsing incoming data, simultaneously validating the request and drop the connection if request's found to be invalid.

The question is: how I'd do any of this? I'm using Node.js version 0.1.97-14-g0055dd1 if this matters.

Thanks for any suggestions.

+1  A: 

Don't know whenever I'm doing this right, but this seems right for me:

var http = require('http'),
    sys = require('sys');

http.createServer(function (req, res) {
    var body = "",
        body_complete = false,
        wait_complete = false;
    sys.debug("Got request");

    // This will be called on each process' completion
    var final_cb = function(err) {
        if (err) throw new Error(err);
        if (body_complete && wait_complete) {
            res.writeHead(200, {'Content-Type': 'text/plain'});
            res.end(body);
        }
    };

    // Async process one: get POST body
    req.addListener('data', function (chunk) {
        sys.debug("Got 'data' event");
        body += chunk;
    });
    req.addListener('end', function () {
        sys.debug("Got 'end' event");
        body_complete = true;
        final_cb(null)
    });

    // Async process two: wait 10ms
    setTimeout(function() { // In real code I'm accessing Redis here.
        sys.debug("Timeout passed");
        if (false) { // Okay, timeout can't go wrong
            res.writeHead(403);
            res.end('Sorry');
        }
        wait_complete = true;
        final_cb(null);
    }, 10);
}).listen(8000);
drdaeman
Because there're no other answers I'm accepting this. Still, I don't know whenever this is the *proper* way or it just happen to work. Suggestions are welcomed.
drdaeman