1

Since node.js is single threaded and many requests run in parallel using asynchronous callbacks or events and any one request doesn't immediately run to completion, is there a risk that the processes from one http request end up sharing variables with other requests, especially when storing data in temporary objects or variables within functions/modules?

In php, for example, each process gets it's own thread and runs to completion (blocks anything else). So there is no way for variables to be accessible across connections/requests.

I tried google searching but didn't find much. Is this even a concern? Is it possible for variables to be unintentionally shared among individual requests from different (or even the same) users?

ciso
  • 2,887
  • 6
  • 33
  • 58

3 Answers3

4

There is only one case where this might be a concern: unintentional global variables.

Consider the following Express route:

app.post('/foo', function(req, res) {
    var user = req.cookies.user;
    token = generateToken(user);

    someAsyncOperation(user, req.body, function(err, result) {
        saveUser(token, result);
        res.send(result);
    });
});

Do you see the error? user is scoped the the function, but token is an implicit global variable that will be shared across all requests.

In this example, it's likely the hypothetical author meant to use a comma instead of a semicolon after the definition of user (which would cause token to be properly scoped). Unfortunately, his finger came down a centimeter northeast and created an easy-to-miss bug.

  • Request A comes in. user is loaded from a cookie, and some kind of token generation function creates a token that should be unique to the user.
  • An asynchronous operation is queued, and the callback function is bound to the scope of request A.
  • The async operation takes some amount of time, so node goes idle.
  • Request B comes in. It initializes a new user in its scope.
  • The global token gets overwritten with request B's token.
  • Another async operation is queued for B; node goes idle again.
  • A's async operation completes.
  • Uh-oh. The result of A's operation is saved using B's token, because that's what token was last set to.
  • B's async operation completes and saves more data to B's token.

In this scenario, nothing is saved to A and two sets of data are saved to B. This could result in everything from strange inconsistencies that are nearly impossible to reproduce and debug all the way up to actual financial loss. (Did I just send B two orders on accident?)

The good news is that it is easy to avoid this problem. Use strict mode. Strict mode makes assignment to implicit globals a ReferenceError among other things. Just add to the top of your js files:

'use strict';

Or run node with the argument:

--use_strict

With strict mode on, you can't accidentally use an implicit global, so this is no longer a problem. Local variables and the req/res objects are safe; the only other area where you might run in to trouble is when you're intentionally using some kind of shared state, but the hazards there would be the same in any other language.

josh3736
  • 139,160
  • 33
  • 216
  • 263
2

Javascript works differently than PHP. The behavior of scope is completely different and is what prevents the problem from being a concern.

The real world analogy is imagine that you have a number of work benches in a line. Your boss comes in and sets some items on a bench to be worked on. While you are working on it, he places more items on the other benches in line.

At a certain point, you reach a stopping point at desk #1 where you will have to wait. You move to desk #2 to begin working there. Once you see that desk #1 is ready again, you go to desk #1 and work some more. Since you have completely different desks, it is very hard to get mixed up. You just need to remember not to carry stuff around. Each function in Node has completely different scope that makes it very hard for node to get mixed up about what it is doing.

function object_init() { this.a = 'a'; return this }

function server_resp(req, res) {
    var obj = object_init();
    if ( req.changeTrue() ) {
         obj.a = 'b';
    }
    function test() {
        longOperation();
        console.log( obj.a );

    }

    test()
}

The above snippet is normal snippet of what could be going on in Node.js application at the very high level. Most javascript applications will have a snippet of code very similar to this.

Your concern is that after longOperation() that Node will return to the wrong instance of the server_resp. The reason that it does not happen is because each request has its own "bench". Node is smart enough to move from one bench to the next without carrying items from one to the next. Node's job is to execute not carry. Each "bench" has its own obj. Each "bench" even has its own test(). This is the way that Javascript works because functions are very closely related to objects.

PHP has a completely different memory and execution model than javascript, which is why javascript can do this securely. PHP is more procedural/OOP while javascript has a more functional flavor.

This is the general explanation of how node works. There could be security vulnerabilities lurking beneath the surface. Depending on the memory model and size checking, an integer overflow could rewrite the memory bank, and let an attacker gain access to a scope that they didn't have access to before. Poor code could widen this hole. For normal code, a mixup between different requests would be close to impossible to pull off.

yxre
  • 3,576
  • 21
  • 20
0

It's not really a concern if you are doing it right, and I don't mean that to be flippant. :-) Most languages have global scopes or shared/shareable data structures. Even with threaded operations this can be a risk, such as the improper use/implementation of a Singleton in a threaded environment. If one takes the time to understand how Javascript works however, and writes code in a way that reflects such understanding, this really shouldn't be a problem.

I would suggest that you can take your lack of turning up much discussion of it in search results, in light of there being A LOT of stuff about javascript on the web, should be reassuring to you that it isn't a big problem.

Take some time to understand (via reading and some experimentation) about how scope and closures work in Javascript, and you should feel much more comfortable about this.

The top two rated answers on this question should be helpful to understanding scope and closures. Other than that, look at some of the various example apps built on Express (and dig into Express and Connect's code as well) and see how they are implemented.

Community
  • 1
  • 1
barry-johnson
  • 3,204
  • 1
  • 17
  • 19