Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
unreleased
==========

* Methods are no longer enumerable on `req.session` object

1.13.1 / 2016-01-29
===================

* deps: parseurl@~1.3.1
- perf: enable strict mode
* deps: uid-safe@~2.1.0
Expand Down
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -412,90 +412,122 @@ The following modules implement a session store that is compatible with this
module. Please make a PR to add additional modules :)

[![★][cassandra-store-image] cassandra-store][cassandra-store-url] An Apache Cassandra-based session store.

[cassandra-store-url]: https://www.npmjs.com/package/cassandra-store
[cassandra-store-image]: https://img.shields.io/github/stars/webcc/cassandra-store.svg?label=%E2%98%85

[![★][cluster-store-image] cluster-store][cluster-store-url] A wrapper for using in-process / embedded
stores - such as SQLite (via knex), leveldb, files, or memory - with node cluster (desirable for Raspberry Pi 2
and other multi-core embedded devices).

[cluster-store-url]: https://www.npmjs.com/package/cluster-store
[cluster-store-image]: https://img.shields.io/github/stars/coolaj86/cluster-store.svg?label=%E2%98%85

[![★][connect-azuretables-image] connect-azuretables][connect-azuretables-url] An [Azure Table Storage](https://azure.microsoft.com/en-gb/services/storage/tables/)-based session store.

[connect-azuretables-url]: https://www.npmjs.com/package/connect-azuretables
[connect-azuretables-image]: https://img.shields.io/github/stars/mike-goodwin/connect-azuretables.svg?label=%E2%98%85

[![★][connect-couchbase-image] connect-couchbase][connect-couchbase-url] A [couchbase](http://www.couchbase.com/)-based session store.

[connect-couchbase-url]: https://www.npmjs.com/package/connect-couchbase
[connect-couchbase-image]: https://img.shields.io/github/stars/christophermina/connect-couchbase.svg?label=%E2%98%85

[![★][connect-dynamodb-image] connect-dynamodb][connect-dynamodb-url] A DynamoDB-based session store.

[connect-dynamodb-url]: https://github.com/ca98am79/connect-dynamodb
[connect-dynamodb-image]: https://img.shields.io/github/stars/ca98am79/connect-dynamodb.svg?label=%E2%98%85

[![★][connect-mssql-image] connect-mssql][connect-mssql-url] A SQL Server-based session store.

[connect-mssql-url]: https://www.npmjs.com/package/connect-mssql
[connect-mssql-image]: https://img.shields.io/github/stars/patriksimek/connect-mssql.svg?label=%E2%98%85

[![★][connect-monetdb-image] connect-monetdb][connect-monetdb-url] A MonetDB-based session store.

[connect-monetdb-url]: https://www.npmjs.com/package/connect-monetdb
[connect-monetdb-image]: https://img.shields.io/github/stars/MonetDB/npm-connect-monetdb.svg?label=%E2%98%85

[![★][connect-mongo-image] connect-mongo][connect-mongo-url] A MongoDB-based session store.

[connect-mongo-url]: https://www.npmjs.com/package/connect-mongo
[connect-mongo-image]: https://img.shields.io/github/stars/kcbanner/connect-mongo.svg?label=%E2%98%85

[![★][connect-mongodb-session-image] connect-mongodb-session][connect-mongodb-session-url] Lightweight MongoDB-based session store built and maintained by MongoDB.

[connect-mongodb-session-url]: https://www.npmjs.com/package/connect-mongodb-session
[connect-mongodb-session-image]: https://img.shields.io/github/stars/mongodb-js/connect-mongodb-session.svg?label=%E2%98%85

[![★][connect-pg-simple-image] connect-pg-simple][connect-pg-simple-url] A PostgreSQL-based session store.

[connect-pg-simple-url]: https://www.npmjs.com/package/connect-pg-simple
[connect-pg-simple-image]: https://img.shields.io/github/stars/voxpelli/node-connect-pg-simple.svg?label=%E2%98%85

[![★][connect-redis-image] connect-redis][connect-redis-url] A Redis-based session store.

[connect-redis-url]: https://www.npmjs.com/package/connect-redis
[connect-redis-image]: https://img.shields.io/github/stars/tj/connect-redis.svg?label=%E2%98%85

[![★][connect-memcached-image] connect-memcached][connect-memcached-url] A memcached-based session store.

[connect-memcached-url]: https://www.npmjs.com/package/connect-memcached
[connect-memcached-image]: https://img.shields.io/github/stars/balor/connect-memcached.svg?label=%E2%98%85

[![★][connect-session-knex-image] connect-session-knex][connect-session-knex-url] A session store using
[Knex.js](http://knexjs.org/), which is a SQL query builder for PostgreSQL, MySQL, MariaDB, SQLite3, and Oracle.

[connect-session-knex-url]: https://www.npmjs.com/package/connect-session-knex
[connect-session-knex-image]: https://img.shields.io/github/stars/llambda/connect-session-knex.svg?label=%E2%98%85

[![★][connect-session-sequelize-image] connect-session-sequelize][connect-session-sequelize-url] A session store using
[Sequelize.js](http://sequelizejs.com/), which is a Node.js / io.js ORM for PostgreSQL, MySQL, SQLite and MSSQL.

[connect-session-sequelize-url]: https://www.npmjs.com/package/connect-session-sequelize
[connect-session-sequelize-image]: https://img.shields.io/github/stars/mweibel/connect-session-sequelize.svg?label=%E2%98%85

[![★][express-mysql-session-image] express-mysql-session][express-mysql-session-url] A session store using native
[MySQL](https://www.mysql.com/) via the [node-mysql](https://github.com/felixge/node-mysql) module.

[express-mysql-session-url]: https://www.npmjs.com/package/express-mysql-session
[express-mysql-session-image]: https://img.shields.io/github/stars/chill117/express-mysql-session.svg?label=%E2%98%85

[![★][connect-sqlite3-image] connect-sqlite3][connect-sqlite3-url] A [SQLite3](https://github.com/mapbox/node-sqlite3) session store modeled after the TJ's `connect-redis` store.

[connect-sqlite3-url]: https://www.npmjs.com/package/connect-sqlite3
[connect-sqlite3-image]: https://img.shields.io/github/stars/rawberg/connect-sqlite3.svg?label=%E2%98%85

[![★][express-nedb-session-image] express-nedb-session][express-nedb-session-url] A NeDB-based session store.

[express-nedb-session-url]: https://www.npmjs.com/package/express-nedb-session
[express-nedb-session-image]: https://img.shields.io/github/stars/louischatriot/express-nedb-session.svg?label=%E2%98%85

[![★][level-session-store-image] level-session-store][level-session-store-url] A LevelDB-based session store.

[level-session-store-url]: https://www.npmjs.com/package/level-session-store
[level-session-store-image]: https://img.shields.io/github/stars/scriptollc/level-session-store.svg?label=%E2%98%85

[![★][mssql-session-store-image] mssql-session-store][mssql-session-store-url] A SQL Server-based session store.

[mssql-session-store-url]: https://www.npmjs.com/package/mssql-session-store
[mssql-session-store-image]: https://img.shields.io/github/stars/jwathen/mssql-session-store.svg?label=%E2%98%85

[![★][nedb-session-store-image] nedb-session-store][nedb-session-store-url] An alternate NeDB-based (either in-memory or file-persisted) session store.

[nedb-session-store-url]: https://www.npmjs.com/package/nedb-session-store
[nedb-session-store-image]: https://img.shields.io/github/stars/JamesMGreene/nedb-session-store.svg?label=%E2%98%85

[![★][sequelstore-connect-image] sequelstore-connect][sequelstore-connect-url] A session store using [Sequelize.js](http://sequelizejs.com/).

[sequelstore-connect-url]: https://www.npmjs.com/package/sequelstore-connect
[sequelstore-connect-image]: https://img.shields.io/github/stars/MattMcFarland/sequelstore-connect.svg?label=%E2%98%85

[![★][session-file-store-image] session-file-store][session-file-store-url] A file system-based session store.

[session-file-store-url]: https://www.npmjs.com/package/session-file-store
[session-file-store-image]: https://img.shields.io/github/stars/valery-barysok/session-file-store.svg?label=%E2%98%85

[![★][session-rethinkdb-image] session-rethinkdb][session-rethinkdb-url] A [RethinkDB](http://rethinkdb.com/)-based session store.

[session-rethinkdb-url]: https://www.npmjs.com/package/session-rethinkdb
[session-rethinkdb-image]: https://img.shields.io/github/stars/llambda/session-rethinkdb.svg?label=%E2%98%85

Expand Down
210 changes: 105 additions & 105 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,135 +184,135 @@ function session(options){
// get the session ID from the cookie
var cookieId = req.sessionID = getcookie(req, name, secrets);

// set-cookie
onHeaders(res, function(){
if (!req.session) {
debug('no session');
return;
var _callback = null;
/**
* Commits the session.
* May be called multiple times and ensures it only runs once,
* Returns true if all commit related tasks are complete when the function returns.
* Returns false it it has async tasks pending.
* If _callback is defined, it is called without arguments once all async tasks are complete.
*/
var commitSession = (function() {
var started = false,
finished = false;
function done() {
finished = true;
if (_callback) {
_callback();
}
}
return function() {
if (started) {
return finished;
}
started = true;
if (shouldDestroy(req)) {
// destroy session
debug('destroying');
store.destroy(req.sessionID, function ondestroy(err) {
if (err) {
defer(next, err);
}
debug('destroyed');
done();
});
return finished;
}
if (!req.session) {
debug('no session');
done();
return finished;
}
// touch session
req.session.touch();

// only send secure cookies via https
var cookie = req.session.cookie;
if (cookie.secure && !issecure(req, trustProxy)) {
debug('not secured');
} else if (shouldSetCookie(req)) {
setcookie(res, name, req.sessionID, secrets[0], cookie.data);
}

var cookie = req.session.cookie;

// only send secure cookies via https
if (cookie.secure && !issecure(req, trustProxy)) {
debug('not secured');
return;
if (shouldSave(req)) {
req.session.save(function onsave(err) {
if (err) {
defer(next, err);
}
done();
});
}
else if (storeImplementsTouch && shouldTouch(req)) {
// store implements touch method
debug('touching');
store.touch(req.sessionID, req.session, function ontouch(err) {
if (err) {
defer(next, err);
}
debug('touched');
done();
});
} else {
done();
}
return finished;
}
})();

if (!shouldSetCookie(req)) {
return;
}

setcookie(res, name, req.sessionID, secrets[0], cookie.data);
});
// commit the session - can be called before or after res.end()
onHeaders(res, commitSession);

// proxy end() to commit the session
var _end = res.end;
var _write = res.write;
var ended = false;

res.end = function end(chunk, encoding) {
if (ended) {
// end has already been called
return false;
}

ended = true;

var ret;
var sync = true;

function writeend() {
if (sync) {
ret = _end.call(res, chunk, encoding);
sync = false;
return;
}

_end.call(res);
}

function writetop() {
if (!sync) {
return ret;
}

if (chunk == null) {
ret = true;
return ret;
}
// commit the session and get the commit status
var committed = commitSession();

var contentLength = Number(res.getHeader('Content-Length'));

if (!isNaN(contentLength) && contentLength > 0) {
// measure chunk
chunk = !Buffer.isBuffer(chunk)
? new Buffer(chunk, encoding)
: chunk;
encoding = undefined;

if (chunk.length !== 0) {
debug('split response');
ret = _write.call(res, chunk.slice(0, chunk.length - 1));
chunk = chunk.slice(chunk.length - 1, chunk.length);
return ret;
}
}

ret = _write.call(res, chunk, encoding);
sync = false;

return ret;
if (committed) {
// all commit activities have completed
return _end.call(res, chunk, encoding);
}

if (shouldDestroy(req)) {
// destroy session
debug('destroying');
store.destroy(req.sessionID, function ondestroy(err) {
if (err) {
defer(next, err);
}

debug('destroyed');
writeend();
});

return writetop();
/*
* commit is still running
*/

// provide a callback to write data
_callback = function() {
_end.call(res, chunk, encoding);
}

// no session to save
if (!req.session) {
debug('no session');
return _end.call(res, chunk, encoding);
if (chunk == null) {
// nothing to do - wait for commit to call the callback
return;
}

// touch session
req.session.touch();

if (shouldSave(req)) {
req.session.save(function onsave(err) {
if (err) {
defer(next, err);
}

writeend();
});

return writetop();
} else if (storeImplementsTouch && shouldTouch(req)) {
// store implements touch method
debug('touching');
store.touch(req.sessionID, req.session, function ontouch(err) {
if (err) {
defer(next, err);
}

debug('touched');
writeend();
});

return writetop();
// write as much data as possible while the commit is running
var ret;
var contentLength = Number(res.getHeader('Content-Length'));
if (!isNaN(contentLength) && contentLength > 0 && chunk.length !== 0) {
// send everything but the last character
chunk = !Buffer.isBuffer(chunk) ? new Buffer(chunk, encoding) : chunk;
encoding = undefined;
debug('split response');
ret = _write.call(res, chunk.slice(0, chunk.length - 1));
chunk = chunk.slice(chunk.length - 1, chunk.length);
} else {
// send everything and change callback
ret = _write.call(res, chunk, encoding);
_callback = _end.bind(res);
}

return _end.call(res, chunk, encoding);
return ret;
};

// generate the session
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "express-session",
"version": "1.13.0",
"version": "1.13.1",
"description": "Simple session middleware for Express",
"author": "TJ Holowaychuk <tj@vision-media.ca> (http://tjholowaychuk.com)",
"contributors": [
Expand Down
Loading