Permalink
Browse files

simplified session storage and added test

  • Loading branch information...
1 parent 9a3a880 commit d099b2d466454e8fbaa4d1072d60d10a2877299a @coolaj86 committed Feb 11, 2012
Showing with 125 additions and 48 deletions.
  1. +39 −45 lib/lib/connect-cors-session.js
  2. +26 −0 lib/lib/cors-session.js
  3. +38 −0 lib/lib/memory-store.js
  4. +2 −1 lib/package.json
  5. +20 −2 test.js
@@ -2,12 +2,15 @@
"use strict";
// TODO use one config and then auto camelcase headers
- var defaultSessionKey = 'userSession'
+ var http = require('http')
+ , UUID = require('node-uuid')
+ , MemoryStore = require('./memory-store')
+ , CorsSession = require('./cors-session')
+ , defaultSessionKey = 'userSession'
, defaultSessionAppKey = 'appSession'
, defaultSessionHeader = 'X-User-Session'
- , sessionHeader = defaultSessionHeader
- , lcSessionHeader = sessionHeader.toLowerCase()
, defaultSessionAppHeader = 'X-App-Session'
+ , resProto = http.ServerResponse.prototype
;
function random() {
@@ -17,81 +20,72 @@
function create(options) {
options = options || {};
- var http = require('http')
- , resProto = http.ServerResponse.prototype
- //, sendJsonProto = resProto.json
- , secret = options.secret || (Math.random() * Date.now()).toString('36').split('').sort(random).join('')
+ var sessionHeader = defaultSessionHeader
+ , lcSessionHeader = sessionHeader.toLowerCase()
, sessionKey = options.sessionKey || defaultSessionKey
, lcSessionKey = sessionKey.toLowerCase()
+ , appSession = {}
, purgeInterval = options.purgeInterval || 10 * 60 * 1000
, maxAge = options.maxAge || 60 * 60 * 1000
- , db = {}
;
- resProto.sessionSendJson = resProto.json;
+ // don't use the prototype?
+ resProto.corsSessionSendJson = resProto.json;
resProto.json = function (data, opts) {
this.meta(sessionKey, this.sessionId);
- this.sessionSendJson(data, opts);
+ this.corsSessionSendJson(data, opts);
};
- // TODO fingerprint to prevent theft by Wireshark sniffers
- // TODO rolling fingerprint that is different for each request
- function createSessionId() {
- return (secret +
- Date.now().toString('36') +
- (Math.random() * 19860616).toString('36')
- ).split('').sort(random).join('').replace(/[\W]/g, '').substr(0, 32);
- }
-
- function purge() {
+ function purge(appSession) {
var now = Date.now()
, val
;
- Object.keys(db).forEach(function (key) {
- val = db[key];
+ Object.keys(appSession).forEach(function (key) {
+ val = appSession[key];
if ((now - val.timestamp) > maxAge) {
- delete db[key];
+ if (appSession[key]) {
+ delete appSession[key].corsStore
+ }
+ delete appSession[key];
}
});
}
- function session(req, res, next) {
+ // TODO fingerprint to prevent theft by Wireshark sniffers
+ // TODO rolling fingerprint that is different for each request
+ function connectSession(req, res, next) {
var sessionId
- , timestamp = Date.now()
;
- // TODO add Cookie support
- if (sessionId = req.headers[lcSessionHeader]) {
- req.sessionId = sessionId;
- } else if (sessionId = req.body && req.body[sessionKey]) {
- req.sessionId = sessionId;
- } else if (sessionId = req.query[sessionKey]) {
- req.sessionId = sessionId;
- } else {
- req.sessionId = sessionId = createSessionId();
- }
+ // TODO add Cookie support?
+ sessionId = req.sessionId = req.headers[lcSessionHeader]
+ || (req.body && req.body[sessionKey])
+ || req.query[sessionKey]
+ || UUID.v4()
+ ;
- if (!(req.session = db[sessionId])) {
- req.session = db[sessionId] = {};
- req.session.virgin = true;
- req.session.createdAt = timestamp;
+ req.session = appSession[sessionId];
+
+ if (!req.session) {
+ req.session = appSession[sessionId] = CorsSession.create();
} else {
delete req.session.virgin;
}
// TODO else if (req.expireSession) { delete a replaced session }
- res.sessionId = req.sessionId;
- req.session.touchedAt = timestamp;
+ req.session.touch();
res.setHeader(sessionHeader, sessionId);
-
- next();
+ // used by res.json
+ res.sessionId = sessionId;
+ next();
}
setInterval(purge, purgeInterval);
- session.headers = [lcSessionHeader];
- return session;
+ // to allow headers through CORS
+ connectSession.headers = [lcSessionHeader];
+ return connectSession;
}
module.exports = create;
@@ -0,0 +1,26 @@
+(function () {
+ "use strict";
+
+ var MemoryStore = require('./memory-store')
+ ;
+
+ function Session() {
+
+ if (!this) {
+ return new Session();
+ }
+ this.virgin = true;
+ this.createdAt = Date.now();
+ this.corsStore = MemoryStore.create();
+ }
+ Session.prototype.touch = function () {
+ this.touchedAt = Date.now();
+ };
+
+ function create() {
+ return new Session();
+ }
+
+ Session.create = create;
+ module.exports = Session;
+}());
@@ -0,0 +1,38 @@
+(function () {
+ "use strict";
+
+ function nextTick(fn, val) {
+ process.nextTick(function () {
+ fn(val);
+ });
+ }
+
+ function Store() {
+ if (!this) {
+ return new Store();
+ }
+ this.store = {};
+ }
+ Store.prototype.get = function (key, fn) {
+ var val = this.store[key]
+ ;
+
+ fn && nextTick(fn, val);
+ return val;
+ };
+ Store.prototype.set = function (key, val, fn) {
+ this.store[key] = val;
+ fn && nextTick(fn);
+ };
+ Store.prototype.delete = function (key, fn) {
+ delete store[key];
+ fn && nextTick(fn);
+ };
+
+ function create() {
+ return new Store();
+ }
+
+ Store.create = create;
+ module.exports = Store;
+}());
View
@@ -2,7 +2,7 @@
"author": "AJ ONeal <coolaj86@gmail.com> (http://coolaj86.info)",
"name": "steve",
"description": "JSON's best friend (a CORS/XHR2 application platform)",
- "version": "0.5.7",
+ "version": "0.5.8",
"repository": {
"type": "git",
"url": "git://github.com/coolaj86/steve.git"
@@ -16,6 +16,7 @@
, "nowww": ">= 1.1.x"
, "connect-xcors": ">= 0.0.0"
, "express-chromeframe": ">= 0.2.0"
+ , "node-uuid": "1.3.x"
},
"devDependencies": {}
}
View
@@ -20,6 +20,11 @@
;
server = connect.createServer(function (req, res, next) {
+ var count
+ ;
+
+ count = req.session.corsStore.get('foo') || 0;
+
res.json({
"url": req.url
//, "adddress": req.socket.address()
@@ -29,7 +34,11 @@
//, "search": req.search
, "path": req.path
, "headers": req.headers
+ , "count": count
});
+
+ count += 1;
+ req.session.corsStore.set('foo', count);
});
server.listen(port, function () {
@@ -45,7 +54,6 @@
var data
;
- server.close();
if (err) {
console.error(err);
return;
@@ -61,7 +69,17 @@
assert.strictEqual(pathname, data.pathname, "pathnames don't match");
//assert.strictEqual(search, data.search, "searchs don't match");
assert.deepEqual(query, data.query, "queries don't match");
- console.log('tests pass (ctrl+c to exit)');
+ assert.strictEqual(0, data.count);
+
+ request.get(fullurl, null, { headers: headers }).when(function (err, ahr, resp2) {
+ if (err) {
+ console.error(err);
+ return;
+ }
+ assert.strictEqual(1, resp2.result.count);
+ server.close();
+ console.log('tests pass (ctrl+c to exit)');
+ });
});
});

0 comments on commit d099b2d

Please sign in to comment.