From 972d1cdeb4918fd01bbeecbc72fadaefe5af4c1f Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Sat, 10 Oct 2015 05:39:55 +0200 Subject: [PATCH] Add rename_commands option --- README.md | 3 +- changelog.md | 1 + index.js | 19 ++++++-- test/conf/rename.conf | 7 +++ test/rename.spec.js | 110 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 135 insertions(+), 5 deletions(-) create mode 100644 test/conf/rename.conf create mode 100644 test/rename.spec.js diff --git a/README.md b/README.md index 4692728f31..c862017d0a 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ redis - a node.js redis client [![Coverage Status](https://coveralls.io/repos/NodeRedis/node_redis/badge.svg?branch=)](https://coveralls.io/r/NodeRedis/node_redis?branch=) [![Windows Tests](https://img.shields.io/appveyor/ci/bcoe/node-redis/master.svg?label=Windows%20Tests)](https://ci.appveyor.com/project/bcoe/node-redis) -This is a complete Redis client for node.js. It supports all Redis commands and focuses on performance. +This is a complete and feature rich Redis client for node.js. It supports all Redis commands and focuses on performance. Install with: @@ -204,6 +204,7 @@ limits total amount of connection tries. Setting this to 1 will prevent any reco * `auth_pass`: *null*; If set, client will run redis auth command on connect. * `family`: *IPv4*; You can force using IPv6 if you set the family to 'IPv6'. See Node.js [net](https://nodejs.org/api/net.html) or [dns](https://nodejs.org/api/dns.html) modules how to use the family type. * `disable_resubscribing`: *false*; If set to `true`, a client won't resubscribe after disconnecting +* `rename_commands`: *null*; pass a object with renamed commands to use those instead of the original functions. See the [redis security topics](http://redis.io/topics/security) for more info. ```js var redis = require("redis"), diff --git a/changelog.md b/changelog.md index 40553fae6c..deef540ea0 100644 --- a/changelog.md +++ b/changelog.md @@ -6,6 +6,7 @@ Changelog Features - Added disable_resubscribing option to prevent a client from resubscribing after reconnecting (@BridgeAR) +- Added rename_commands options to handle renamed commands from the redis config (@digmxl & @BridgeAR) Bugfixes diff --git a/index.js b/index.js index f28f96a39f..c1477dc06a 100644 --- a/index.js +++ b/index.js @@ -42,11 +42,18 @@ function RedisClient(stream, options) { this.connected = false; this.ready = false; this.connections = 0; - if (this.options.socket_nodelay === undefined) { - this.options.socket_nodelay = true; + if (options.socket_nodelay === undefined) { + options.socket_nodelay = true; } - if (this.options.socket_keepalive === undefined) { - this.options.socket_keepalive = true; + if (options.socket_keepalive === undefined) { + options.socket_keepalive = true; + } + if (options.rename_commands) { + for (var command in options.rename_commands) { + if (options.rename_commands.hasOwnProperty(command)) { + options.rename_commands[command.toLowerCase()] = options.rename_commands[command]; + } + } } this.should_buffer = false; this.command_queue_high_water = options.command_queue_high_water || 1000; @@ -720,6 +727,10 @@ RedisClient.prototype.send_command = function (command, args, callback) { elem_count = args.length + 1; + if (typeof this.options.rename_commands !== 'undefined' && this.options.rename_commands[command]) { + command = this.options.rename_commands[command]; + } + // Always use 'Multi bulk commands', but if passed any Buffer args, then do multiple writes, one for each arg. // This means that using Buffers in commands is going to be slower, so use Strings if you don't already have a Buffer. diff --git a/test/conf/rename.conf b/test/conf/rename.conf new file mode 100644 index 0000000000..4da225053f --- /dev/null +++ b/test/conf/rename.conf @@ -0,0 +1,7 @@ +port 6379 +bind ::1 127.0.0.1 +unixsocket /tmp/redis.sock +unixsocketperm 755 +rename-command SET 807081f5afa96845a02816a28b7258c3 +rename-command GET f397808a43ceca3963e22b4e13deb672 +rename-command GETRANGE 9e3102b15cf231c4e9e940f284744fe0 diff --git a/test/rename.spec.js b/test/rename.spec.js new file mode 100644 index 0000000000..52ee7a4fe4 --- /dev/null +++ b/test/rename.spec.js @@ -0,0 +1,110 @@ +'use strict'; + +var assert = require("assert"); +var config = require("./lib/config"); +var helper = require('./helper'); +var redis = config.redis; + +describe("rename commands", function () { + before(function (done) { + helper.stopRedis(function () { + helper.startRedis('./conf/rename.conf', done); + }); + }); + + helper.allTests(function(parser, ip, args) { + + describe("using " + parser + " and " + ip, function () { + var client = null; + + afterEach(function () { + client.end(); + }); + + it("allows to use renamed functions", function (done) { + if (helper.redisProcess().spawnFailed()) this.skip(); + + client = redis.createClient({ + rename_commands: { + set: '807081f5afa96845a02816a28b7258c3', + GETRANGE: '9e3102b15cf231c4e9e940f284744fe0' + } + }); + + client.set('key', 'value', function(err, reply) { + assert.strictEqual(reply, 'OK'); + }); + + client.get('key', function(err, reply) { + assert.strictEqual(err.message, "ERR unknown command 'get'"); + assert.strictEqual(err.command, 'GET'); + assert.strictEqual(reply, undefined); + }); + + client.getrange('key', 1, -1, function(err, reply) { + assert.strictEqual(reply, 'alue'); + assert.strictEqual(err, null); + done(); + }); + }); + + it("should also work with multi", function (done) { + if (helper.redisProcess().spawnFailed()) this.skip(); + + client = redis.createClient({ + rename_commands: { + SET: '807081f5afa96845a02816a28b7258c3', + getrange: '9e3102b15cf231c4e9e940f284744fe0' + } + }); + + client.multi([['set', 'key', 'value']]).exec(function (err, res) { + assert.strictEqual(res[0], 'OK'); + }); + + var multi = client.multi(); + multi.getrange('key', 1, -1); + multi.exec(function (err, res) { + assert(!err); + assert.strictEqual(res.length, 1); + assert.strictEqual(res[0], 'alue'); + done(); + }); + }); + + it("should also work with multi and abort transaction", function (done) { + if (helper.redisProcess().spawnFailed()) this.skip(); + + client = redis.createClient({ + rename_commands: { + SET: '807081f5afa96845a02816a28b7258c3', + getrange: '9e3102b15cf231c4e9e940f284744fe0' + } + }); + + var multi = client.multi(); + multi.get('key'); + multi.getrange('key', 1, -1, function(err, reply) { + assert.strictEqual(reply, 'alue'); + assert.strictEqual(err, null); + }); + multi.exec(function (err, res) { + assert(err); + assert.strictEqual(err.message, 'EXECABORT Transaction discarded because of previous errors.'); + assert.strictEqual(err.errors[0].message, "ERR unknown command 'get'"); + assert.strictEqual(err.errors[0].command, 'GET'); + assert.strictEqual(err.code, 'EXECABORT'); + assert.strictEqual(err.errors[0].code, 'ERR'); + done(); + }); + }); + + }); + }); + + after(function (done) { + helper.stopRedis(function () { + helper.startRedis('./conf/redis.conf', done); + }); + }); +});