Skip to content

Commit e89bcec

Browse files
author
Ruben Bridgewater
committed
Deprecate and warn on null / undefined arguments
1 parent 16a1d69 commit e89bcec

File tree

7 files changed

+43
-41
lines changed

7 files changed

+43
-41
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ limits total amount of connection tries. Setting this to 1 will prevent any reco
211211
* `auth_pass`: *null*; If set, client will run redis auth command on connect.
212212
* `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.
213213
* `disable_resubscribing`: *false*; If set to `true`, a client won't resubscribe after disconnecting
214+
* `to_empty_string`: *null*; convert any undefined or null command argument to an empty string. Be careful using this
214215
* `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.
215216
* `tls`: an object containing options to pass to [tls.connect](http://nodejs.org/api/tls.html#tls_tls_connect_port_host_options_callback),
216217
to set up a TLS connection to Redis (if, for example, it is set up to be accessible via a tunnel).

index.js

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -719,39 +719,49 @@ RedisClient.prototype.send_command = function (command, args, callback) {
719719
callback = process.domain.bind(callback);
720720
}
721721

722-
if (command === 'set' || command === 'setex') {
723-
// if the value is undefined or null and command is set or setx, need not to send message to redis
724-
if (args[args.length - 1] === undefined || args[args.length - 1] === null) {
725-
command = command.toUpperCase();
726-
err = new Error('send_command: ' + command + ' value must not be undefined or null');
727-
err.command = command;
728-
this.callback_emit_error(callback, err);
729-
// Singal no buffering
730-
return true;
731-
}
732-
}
733-
734722
for (i = 0; i < args.length; i += 1) {
735-
if (Buffer.isBuffer(args[i])) {
723+
if (typeof args[i] === 'string') {
724+
// 30000 seemed to be a good value to switch to buffers after testing and checking the pros and cons
725+
if (args[i].length > 30000) {
726+
big_data = true;
727+
args[i] = new Buffer(args[i], 'utf8');
728+
if (this.pipeline !== 0) {
729+
this.pipeline += 2;
730+
this.writeDefault = this.writeBuffers;
731+
}
732+
}
733+
} else if (args[i] === null) {
734+
if (!this.options.to_empty_string) { // > 2 // ( 2 + 3 where 3 stands for both, null and undefined and 3 for null)
735+
console.warn(
736+
'node_redis: Deprecated: The %s command contains a "null" argument.\n' +
737+
'This is converted to a "null" string now and will return an error from v.3.0 on.\n' +
738+
'If you wish to convert null to an empty string instead, please use the "to_empty_string" option.', command.toUpperCase()
739+
);
740+
args[i] = 'null'; // Backwards compatible :/
741+
} else {
742+
args[i] = '';
743+
}
744+
} else if (typeof args[i] === 'object') { // Buffer.isBuffer(args[i])) {
736745
buffer_args = true;
737746
if (this.pipeline !== 0) {
738747
this.pipeline += 2;
739748
this.writeDefault = this.writeBuffers;
740749
}
741-
} else if (typeof args[i] !== 'string') {
742-
args[i] = String(args[i]);
743-
// 30000 seemed to be a good value to switch to buffers after testing and checking the pros and cons
744-
} else if (args[i].length > 30000) {
745-
big_data = true;
746-
args[i] = new Buffer(args[i]);
747-
if (this.pipeline !== 0) {
748-
this.pipeline += 2;
749-
this.writeDefault = this.writeBuffers;
750+
} else if (args[i] === undefined) {
751+
if (!this.options.to_empty_string) {
752+
console.warn(
753+
'node_redis: Deprecated: The %s command contains a "undefined" argument.\n' +
754+
'This is converted to a "undefined" string now and will return an error from v.3.0 on.\n' +
755+
'If you wish to convert undefined to an empty string instead, please use the "to_empty_string" option.', command.toUpperCase()
756+
);
757+
args[i] = 'undefined'; // Backwards compatible :/
758+
} else {
759+
args[i] = '';
750760
}
751761
}
752762
}
753763

754-
command_obj = new Command(command, args, false, buffer_args, callback);
764+
command_obj = new Command(command, args, buffer_args, callback);
755765

756766
if (!this.ready && !this.send_anyway || !stream.writable) {
757767
if (this.closing || !this.enable_offline_queue) {
@@ -812,9 +822,9 @@ RedisClient.prototype.send_command = function (command, args, callback) {
812822

813823
for (i = 0; i < args.length; i += 1) {
814824
arg = args[i];
815-
if (typeof arg === 'string') {
825+
if (typeof arg !== 'object') { // string; number; boolean
816826
this.write('$' + Buffer.byteLength(arg) + '\r\n' + arg + '\r\n');
817-
} else {
827+
} else { // buffer
818828
this.write('$' + arg.length + '\r\n');
819829
this.write(arg);
820830
this.write('\r\n');

lib/command.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22

33
// This Command constructor is ever so slightly faster than using an object literal, but more importantly, using
44
// a named constructor helps it show up meaningfully in the V8 CPU profiler and in heap snapshots.
5-
function Command(command, args, sub_command, buffer_args, callback) {
5+
function Command(command, args, buffer_args, callback) {
66
this.command = command;
77
this.args = args;
8-
this.sub_command = sub_command;
98
this.buffer_args = buffer_args;
109
this.callback = callback;
1110
}

test/commands/incr.spec.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ describe("The 'incr' method", function () {
4343
describe("when connected and a value in Redis", function () {
4444
var client;
4545

46-
// Also, why tf were these disabled for hiredis? They work just fine.
4746
before(function (done) {
4847
/*
4948
9007199254740992 -> 9007199254740992

test/commands/set.spec.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ describe("The 'set' method", function () {
113113
describe("with undefined 'key' and missing 'value' parameter", function () {
114114
it("emits an error without callback", function (done) {
115115
client.on('error', function (err) {
116-
assert.equal(err.message, 'send_command: SET value must not be undefined or null');
116+
assert.equal(err.message, "ERR wrong number of arguments for 'set' command");
117117
assert.equal(err.command, 'SET');
118118
done();
119119
});
@@ -132,13 +132,10 @@ describe("The 'set' method", function () {
132132

133133
it("emit an error without any parameters", function (done) {
134134
client.once("error", function (err) {
135-
assert.equal(err.message, 'send_command: SET value must not be undefined or null');
135+
assert.equal(err.message, "ERR wrong number of arguments for 'set' command");
136136
assert.equal(err.command, 'SET');
137137
done();
138138
});
139-
140-
// This was not supported not to throw earlier and was added by the test refactoring
141-
// https://github.com/NodeRedis/node_redis/commit/eaca486ab1aecd1329f7452ad2f2255b1263606f
142139
client.set();
143140
});
144141
});

test/commands/setex.spec.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,14 @@ describe("The 'setex' method", function () {
2121

2222
it('sets a key with an expiry', function (done) {
2323
client.setex(["setex key", "100", "setex val"], helper.isString("OK"));
24-
client.exists(["setex key"], helper.isNumber(1));
24+
var buffering = client.exists(["setex key"], helper.isNumber(1));
25+
assert(typeof buffering === 'boolean');
2526
client.ttl(['setex key'], function (err, ttl) {
26-
assert.ok(ttl > 0);
27+
assert(ttl > 0);
2728
return done();
2829
});
2930
});
3031

31-
it('returns an error if no value is provided', function (done) {
32-
var buffering = client.SETEX(["setex key", "100", undefined], helper.isError(done));
33-
assert(typeof buffering === 'boolean');
34-
});
35-
3632
afterEach(function () {
3733
client.end(true);
3834
});

test/connection.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ describe("connection tests", function () {
9090
});
9191

9292
client.on("reconnecting", function (params) {
93-
client.end();
93+
client.end(true);
9494
setTimeout(done, 100);
9595
});
9696
});

0 commit comments

Comments
 (0)