node.js provides you a very fast HTTP server, however you have to implement many features by yourself, or you can try to find modules/projects developed for node.js. I prefer the first way and actually this the most fun part of it.
Session handling requires that you start a session on server side. Depending on if you know that the request is from a new source or the same source, you should either start a new session or resume an old session. To understand if you are dealing with the same source, in the HTTP world, cookies is the best solution. (You can also use URLs instead of cookies but for practical reasons you would like focus on clients that support cookies)
What we do is to store a unique session key (Session ID or SID) in the cookie. That way, each time a request from the source hits your server you will get a SID which you can compare in your list of session ids to find the session linked to source.
I’ve implemented a session logic the code of which can be found below. The code is not reusable alone, because it depends on a simple framework that I’m working on, but the code can give insight about how session handling could be implemented.
Although the current implementation is an object hash in memory where keys are the SIDs and the values are objects that keep the session related data, I’ve kept a callback parameter to support async calls in the future. (Probably I’ll use something like memcached next time to keep session information)
The logic is as follows:
- If the request has a cookie with the name ‘SESSIONID’ try to find the session information. If there is no session information or session is timed out, start a new session immediately.
- Add the new/old session id to the cookie of the response.
- set/get methods are used to change or access values stored in sessions. Probably, an authentication system may use these functions to store login information of a user. As you can realize, they are also async function expecting a callback from the caller.
I’ll write later on the cookie logic. In the meantime, I may also improve session logic with the support of memcache.
var sessions = {};
var SID_STRING = 'SESSIONID';
var TIMEOUT = 3*60*1000;
exports.start = function(req, res, callback) {
var setSid = function(sid) {
sessions[sid]['__timeout'] = Date.now() + TIMEOUT;
req.cookies[SID_STRING] = sid;
gj.cookie.set(res,SID_STRING,sid);
callback.apply(undefined,[null]);
}
if(req.cookies[SID_STRING] != undefined) {
sid = req.cookies[SID_STRING];
} else {
createNew(req, setSid);
return;
}
if(sessions[sid] == undefined) {
createNew(req, setSid);
} else if(sessions[sid]['__timeout'] < Date.now()) {
delete sessions[sid];
createNew(req, setSid);
} else {
setSid(sid);
}
}
var createNew = function(req, callback) {
sid = gj.util.md5.hash(req.socket.remoteAddress + "" + Date.now());
sessions[sid] = {__timeout:Date.now() + TIMEOUT};
callback.apply(undefined,[sid]);
}
exports.end = function(req, res) {
delete sessions[res.cookies[SID_STRING]];
gj.cookie.unset(res,SID_STRING);
}
exports.set = function(req, key, value, callback) {
if(req.cookies == undefined || req.cookies[SID_STRING] == undefined) {
callback.apply(undefined,["No session defined"]);
}
var sid = req.cookies[SID_STRING];
var session_object = sessions[sid];
if(session_object) {
session_object[key] = value;
callback.apply(undefined,[null]);
} else {
callback.apply(undefined,["Can't set session value"]);
}
}
exports.get = function(req, key, callback) {
if(req.cookies == undefined || req.cookies[SID_STRING] == undefined) {
callback.apply(undefined,[null]);
}
var sid = req.cookies[SID_STRING];
var session_object = sessions[sid];
if(session_object) {
callback.apply(undefined, [session_object[key]]);
} else {
callback.apply(undefined, [null]);
}
}