What's wrong here?
res.render('/somepage', {user:req.session.user})
It leads to
Converting circular structure to JSONerrors, (results in session element that has a circular user reference.)
exports.home = function (req, res) {
var entityFactory = new require('../lib/entity-factory.js').EntityFactory();
entityFactory.get_job_task_lists({
callback : function (err, job_task_lists) {
res.render('home.jade', {
locals:{
title: 'Logged in.',
user:req.session.user, // does not work
job_task_lists:job_task_lists || []
}
});
}
});
};
I added some logging in node_modules/express/node_modules/connect/lib/middleware/session/memory.js
MemoryStore.prototype.set = function(sid, sess, fn){ var self = this; process.nextTick(function(){ console.log(sess); //this is giving the output listed self.sessions[sid] = JSON.stringify(sess); ...
This is what I expect the session to look like, in terms of structure:
{ lastAccess: 1330979534026, cookie: { path: '/', httpOnly: true, _expires: Tue, 06 Mar 2012 00:32:14 GMT, originalMaxAge: 14399999 }, user: // this is the object I added to the session { id: 1, username: 'admin', password: '8e3f8d3a98481a9073d2ab69f93ce73b', creation_date: Mon, 05 Mar 2012 18:08:55 GMT } }
But here's what I find:
{ lastAccess: 1330979534079, // new session cookie: { path: '/', httpOnly: true, _expires: Tue, 06 Mar 2012 00:32:14 GMT, originalMaxAge: 14399999 }, user: // but here it is again, except now it's a mashup, // containing members it shouldn't have, like locals, // and, well, everything but the first 4 properties { id: 1, username: 'admin', password: '8e3f8d3a98481a9073d2ab69f93ce73b', creation_date: '2012-03-05T18:08:55.701Z', locals: { title: 'Logged in.', user: [Circular], //and now it's circular job_task_lists: [Object] }, title: 'Logged in.', user: [Circular], job_task_lists: [ [Object], [Object], [Object], getById: [Function] ], attempts: [ '/home/dan/development/aqp/views/home.jade' ], scope: {}, parentView: undefined, root: '/home/dan/development/aqp/views', defaultEngine: 'jade', settings: { env: 'development', hints: true, views: '/home/dan/development/aqp/views', 'view engine': 'jade' }, app: { stack: [Object], connections: 6, allowHalfOpen: true, _handle: [Object], _events: [Object], httpAllowHalfOpen: false, cache: [Object], settings: [Object], redirects: {}, isCallbacks: {}, _locals: [Object], dynamicViewHelpers: {}, errorHandlers: [], route: '/', routes: [Object], router: [Getter], __usedRouter: true }, partial: [Function], hint: true, filename: '/home/dan/development/aqp/views/home.jade', layout: false, isPartial: true } } node.js:201 throw e; // process.nextTick error, or 'error' event on first tick ^ TypeError: Converting circular structure to JSON at Object.stringify (native) at Array.0 (/home/dan/development/aqp/node_modules/express/node_modules/connect/lib/middleware/session/memory.js:77:31) at EventEmitter._tickCallback (node.js:192:40)
See how the user object is nested?
It looks like the session is being used to transfer objects to the view.
Here's my only middleware (it only reads from the session):
function requiresAuthentication(req, res, next){ if (req.session.user){ next(); } else { next(new Error('Unauthorized. Please log in with a valid account.')) } }
and the only time I modify the req.session is in this route:
app.post('/home', function (req,res,next) { var auth = require('./lib/authentication'); auth.authenticate_user(req.body.user, function (user) { if (user){ req.session.user = user; console.log('authenticated'); res.redirect(req.body.redir || '/home'); //next(); } else { console.log('not authenticated'); res.render('logins/new.jade', {title: 'Login Failed', redir:''}) } }); });
I don't have much else going on in my application yet, as it's still quite young. I know I'm not mangling the session anywhere myself; I checked.
I did some more testing, and it appears this is only an issue when I then try to use the local variable on a page. For instance, here is my view home.jade
div(data-role="page") div(data-role="header") a(href='/logout', data-icon='delete', data-ajax="false") Log out h1= title a(href='/account', data-icon='info', data-ajax="false") Account != partial('user', user) each jtl in job_task_lists div(id=jtl.name, class = 'draggable_item', style='border:2px solid black;') #{jtl.name} - #{jtl.description} a(data-icon='plus') div(data-role="footer") h3 footer script(src="/javascripts/home.js")
If I comment out the user partial, it renders, else I get this Converting circular structure to JSON
issue.
UPDATE So after hooking up eclipse and the v8 debugger, I have been stepping through the code and I know where the mashup of session and user objects is occurring,
in node_modules/connect/lib/middleware/session/session.js
utils.union ends up mashing the members of the user object into the session, causing the circular reference. I'm just not sure why (admittedly probably my code)
This was a problem with session data being modified in a view.
After much digging, I found that it was a bug in the way partials are handled in 2.5.8. I submitted an issue, and subsequently a patch. (in case anyone needs this info at a future date) as npm is still serving up Express 2.5.8 AFAIK.
Thanks for your help @freakish and @Ryan
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With