From f0934e888c3f26a886f02b26c31d8b0a49899c78 Mon Sep 17 00:00:00 2001 From: Patrick Sullivan Date: Wed, 22 Mar 2017 11:55:40 -0700 Subject: [PATCH] fix: non-overwriting touch semantic support. See issue #27 --- Readme.md | 1 + lib/connect-memcached.js | 36 +++++++++++++++++++++++++++++++----- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/Readme.md b/Readme.md index 9bf540d..5ca8441 100644 --- a/Readme.md +++ b/Readme.md @@ -50,6 +50,7 @@ http.createServer(app).listen(9341, function() { - `ttl` An optional parameter used for setting the default TTL - `secret` An optional secret can be used to encrypt/decrypt session contents. - `algorithm` An optional algorithm parameter may be used, but must be valid based on returned `crypto.getCiphers()`. The current default is `aes-256-ctr` and was chosen based on the following [information](http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html) +- `serverSupportsTouch` Set true if your memcached server version is at least 1.4.14 to enable the more efficient touch protocol. - ... Rest of given option will be passed directly to the node-memcached constructor. For details see [node-memcached](http://github.com/3rd-Eden/node-memcached). diff --git a/lib/connect-memcached.js b/lib/connect-memcached.js index 4921f03..e24dec0 100644 --- a/lib/connect-memcached.js +++ b/lib/connect-memcached.js @@ -31,6 +31,7 @@ module.exports = function(session) { options = options || {}; Store.call(this, options); + this.serverSupportsTouch = options.serverSupportsTouch; this.prefix = options.prefix || ''; this.ttl = options.ttl; if (!options.client) { @@ -107,8 +108,7 @@ module.exports = function(session) { sid = this.getKey(sid); try { - var maxAge = sess.cookie.maxAge; - var ttl = this.ttl || ('number' == typeof maxAge ? maxAge / 1000 | 0 : oneDay); + var ttl = computeTtl.call(this, sess); var sess = JSON.stringify((this.secret) ? encryptData.call(this, JSON.stringify(sess), this.secret, this.algorithm) : @@ -161,10 +161,36 @@ module.exports = function(session) { * @api public */ - MemcachedStore.prototype.touch = function (sid, sess, fn) { - this.set(sid, sess, fn); - } + MemcachedStore.prototype.touch = function (sid, sess, fn) { + sid = this.getKey(sid); + try { + var ttl = computeTtl.call(this, sess); + var self = this; + + // memcached.touch support introduced in 1.4.8 and buggy until 1.4.14 + // when touch not supported implement it using get+set as modelled in MemoryStore + // Memcached.version is not robust so we use options flag to disable work-around + + if (this.serverSupportsTouch) { + this.client.touch(sid, ttl, ensureCallback(fn)); + } else { + self.client.get(sid, function(err, data) { + if (err) { + return fn && fn(err); + } + self.client.set(sid, data, ttl, ensureCallback(fn)); + }); + } + } catch (err) { + fn && fn(err); + } + } + + function computeTtl(sess) { + var maxAge = sess.cookie.maxAge; + return this.ttl || ('number' == typeof maxAge ? maxAge / 1000 | 0 : oneDay); + } function encryptData(plaintext){ var pt = encrypt.call(this, this.secret, plaintext, this.algo)