node.jsexpresssocket.ionowjs-sockets

Socket.io via XHR-Polling not passing cookies


I am attempting to combine Express (3.x) with NowJS (which is largely a wrapper around Socket.io) to create a real-time application that first requires that you log in. I'm admittedly new to Node, but I have a pretty good handle on how each package works separately. However, accessing Express Session information from NowJS is giving me fits.

The problem seems to be that since I am forced to use XHR-Polling (using Heroku as a hosting platform), I am not able to easily access cookie information within the Socket.io authentication method. In the code below for authFunction, "data.headers.cookie" is undefined. In a roundabout way (within Now.js code), this is leaving "this.user.cookie" empty (but not undefined) in the nowjs.on("connect",...) callback. That in turn leaves me unable to grab the session information.

From reading around, it seems like the cookie might only be available if using websockets. Without the cookie, I have no idea which user is making calls to the server other than a random identifier which gets generated for them.

Can anyone suggest how to approach this? Do I need to manually send the cookie from the client side upon establishing connection to the Now.js server?

var app = express();

app.configure(function(){
  app.set('port', process.env.PORT || 3000);
  app.set('views', __dirname + '/views');
  app.engine('html', consolidate.swig);
  app.set('view engine', 'html');

  app.use(express.favicon());
  app.use(express.logger('dev'));
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(express.cookieParser());
  app.use(express.session({ secret: "secrethere" , store: sessionStore}));

  app.use(express.static(path.join(__dirname, 'public')));
  app.use(app.router);
});

app.configure('development', function(){
  app.use(express.errorHandler({dumpExceptions: true, showStack: true}));
});

//Map the routes
var routes = require('./routes/routes')(db);
app.get[...] //routes defined here

var server = http.createServer(app, {cookieKey: 'connect.sid'});
server.listen(app.get('port'), function(){
  console.log("Express server listening on port " + app.get('port'));
});

var parseCookie = require('express/node_modules/connect').utils.parseCookie;
var authFunction = function (data, accept) {
// check if there's a cookie header
if (data.headers.cookie) {
    // if there is, parse the cookie
    data.cookie = parseCookie(data.headers.cookie);

    // note that you will need to use the same key to grad the
    // session id, as you specified in the Express setup.
    data.sessionID = data.cookie['connect.sid'];
} else {
   // if there isn't, turn down the connection with a message
   // and leave the function.
   return accept('No cookie transmitted.', false);
}

// accept the incoming connection
accept(null, true);
};

var everyone = nowjs.initialize(server, {socketio: {transports: ['xhr-polling', 'jsonp-polling'], authorization: authFunction}});

nowjs.on('connect', function (socket) {
//TODO - This will need to be based on the URL that is being visited, or
//similar to establish that users are viewing the same thing
var sid = unescape(this.user.cookie["connect.sid"]); //# you DO have to unescape the session id!

sessionStore.get(sid, function(err, sess){
    console.log("That group who joined? his userId is " + sess.userId)
});

var newRoom = "group";//this.user.session;//.groupName;
var newGroup = nowjs.getGroup(newRoom);
this.now.serverRoom = newRoom;
newGroup.addUser(this.user.clientId);
});

edit: I would of course prefer simple solutions like the top answer here: Session support in Now.js, but that does not work for me for (likely) the same reason - my "cookie" is empty and does not contain the "connect.sid" key.


Solution

  • After a significant amount of trying different things, I realized that this actually has to do with the environment I was using (Cloud9 IDE).

    When debugging with Cloud9, they give you a nice url to walk through your site at "http://[projectname].[username].c9.io". However, NowJS sends its requests to "http://project-[unique ID].rhcloud.com/socket.io/1/xhr-polling/...". This was not prompting the cookie to be sent along with the request, since it was not the same host as the cookie is associated with (okay, terminology may be a little off here).

    To resolve this issue, I am using "http://project-[unique ID].rhcloud.com/..." as my base for debugging, and it seems to be working 100% properly. Heroku seems to not have this problem, as all requests (regular page requests and socketio) are going through the same host.