redis-client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +190 -0
  3. data/CHANGELOG.md +3 -0
  4. data/Gemfile +23 -0
  5. data/Gemfile.lock +67 -0
  6. data/LICENSE.md +21 -0
  7. data/README.md +347 -0
  8. data/Rakefile +86 -0
  9. data/ext/redis_client/hiredis/extconf.rb +54 -0
  10. data/ext/redis_client/hiredis/hiredis_connection.c +696 -0
  11. data/ext/redis_client/hiredis/vendor/.gitignore +9 -0
  12. data/ext/redis_client/hiredis/vendor/.travis.yml +131 -0
  13. data/ext/redis_client/hiredis/vendor/CHANGELOG.md +364 -0
  14. data/ext/redis_client/hiredis/vendor/CMakeLists.txt +165 -0
  15. data/ext/redis_client/hiredis/vendor/COPYING +29 -0
  16. data/ext/redis_client/hiredis/vendor/Makefile +308 -0
  17. data/ext/redis_client/hiredis/vendor/README.md +664 -0
  18. data/ext/redis_client/hiredis/vendor/adapters/ae.h +130 -0
  19. data/ext/redis_client/hiredis/vendor/adapters/glib.h +156 -0
  20. data/ext/redis_client/hiredis/vendor/adapters/ivykis.h +84 -0
  21. data/ext/redis_client/hiredis/vendor/adapters/libev.h +179 -0
  22. data/ext/redis_client/hiredis/vendor/adapters/libevent.h +175 -0
  23. data/ext/redis_client/hiredis/vendor/adapters/libuv.h +117 -0
  24. data/ext/redis_client/hiredis/vendor/adapters/macosx.h +115 -0
  25. data/ext/redis_client/hiredis/vendor/adapters/qt.h +135 -0
  26. data/ext/redis_client/hiredis/vendor/alloc.c +86 -0
  27. data/ext/redis_client/hiredis/vendor/alloc.h +91 -0
  28. data/ext/redis_client/hiredis/vendor/appveyor.yml +24 -0
  29. data/ext/redis_client/hiredis/vendor/async.c +887 -0
  30. data/ext/redis_client/hiredis/vendor/async.h +147 -0
  31. data/ext/redis_client/hiredis/vendor/async_private.h +75 -0
  32. data/ext/redis_client/hiredis/vendor/dict.c +352 -0
  33. data/ext/redis_client/hiredis/vendor/dict.h +126 -0
  34. data/ext/redis_client/hiredis/vendor/fmacros.h +12 -0
  35. data/ext/redis_client/hiredis/vendor/hiredis-config.cmake.in +13 -0
  36. data/ext/redis_client/hiredis/vendor/hiredis.c +1174 -0
  37. data/ext/redis_client/hiredis/vendor/hiredis.h +336 -0
  38. data/ext/redis_client/hiredis/vendor/hiredis.pc.in +12 -0
  39. data/ext/redis_client/hiredis/vendor/hiredis_ssl-config.cmake.in +13 -0
  40. data/ext/redis_client/hiredis/vendor/hiredis_ssl.h +157 -0
  41. data/ext/redis_client/hiredis/vendor/hiredis_ssl.pc.in +12 -0
  42. data/ext/redis_client/hiredis/vendor/net.c +612 -0
  43. data/ext/redis_client/hiredis/vendor/net.h +56 -0
  44. data/ext/redis_client/hiredis/vendor/read.c +739 -0
  45. data/ext/redis_client/hiredis/vendor/read.h +129 -0
  46. data/ext/redis_client/hiredis/vendor/sds.c +1289 -0
  47. data/ext/redis_client/hiredis/vendor/sds.h +278 -0
  48. data/ext/redis_client/hiredis/vendor/sdsalloc.h +44 -0
  49. data/ext/redis_client/hiredis/vendor/sockcompat.c +248 -0
  50. data/ext/redis_client/hiredis/vendor/sockcompat.h +92 -0
  51. data/ext/redis_client/hiredis/vendor/ssl.c +544 -0
  52. data/ext/redis_client/hiredis/vendor/test.c +1401 -0
  53. data/ext/redis_client/hiredis/vendor/test.sh +78 -0
  54. data/ext/redis_client/hiredis/vendor/win32.h +56 -0
  55. data/lib/redis-client.rb +3 -0
  56. data/lib/redis_client/buffered_io.rb +149 -0
  57. data/lib/redis_client/config.rb +174 -0
  58. data/lib/redis_client/connection.rb +86 -0
  59. data/lib/redis_client/hiredis_connection.rb +78 -0
  60. data/lib/redis_client/pooled.rb +86 -0
  61. data/lib/redis_client/resp3.rb +225 -0
  62. data/lib/redis_client/sentinel_config.rb +134 -0
  63. data/lib/redis_client/version.rb +5 -0
  64. data/lib/redis_client.rb +438 -0
  65. data/redis-client.gemspec +34 -0
  66. metadata +125 -0
@@ -0,0 +1,664 @@
1
+ [![Build Status](https://travis-ci.org/redis/hiredis.png)](https://travis-ci.org/redis/hiredis)
2
+
3
+ **This Readme reflects the latest changed in the master branch. See [v1.0.0](https://github.com/redis/hiredis/tree/v1.0.0) for the Readme and documentation for the latest release ([API/ABI history](https://abi-laboratory.pro/?view=timeline&l=hiredis)).**
4
+
5
+ # HIREDIS
6
+
7
+ Hiredis is a minimalistic C client library for the [Redis](http://redis.io/) database.
8
+
9
+ It is minimalistic because it just adds minimal support for the protocol, but
10
+ at the same time it uses a high level printf-alike API in order to make it
11
+ much higher level than otherwise suggested by its minimal code base and the
12
+ lack of explicit bindings for every Redis command.
13
+
14
+ Apart from supporting sending commands and receiving replies, it comes with
15
+ a reply parser that is decoupled from the I/O layer. It
16
+ is a stream parser designed for easy reusability, which can for instance be used
17
+ in higher level language bindings for efficient reply parsing.
18
+
19
+ Hiredis only supports the binary-safe Redis protocol, so you can use it with any
20
+ Redis version >= 1.2.0.
21
+
22
+ The library comes with multiple APIs. There is the
23
+ *synchronous API*, the *asynchronous API* and the *reply parsing API*.
24
+
25
+ ## Upgrading to `1.0.2`
26
+
27
+ <span style="color:red">NOTE: v1.0.1 erroneously bumped SONAME, which is why it is skipped here.</span>
28
+
29
+ Version 1.0.2 is simply 1.0.0 with a fix for [CVE-2021-32765](https://github.com/redis/hiredis/security/advisories/GHSA-hfm9-39pp-55p2). They are otherwise identical.
30
+
31
+ ## Upgrading to `1.0.0`
32
+
33
+ Version 1.0.0 marks the first stable release of Hiredis.
34
+ It includes some minor breaking changes, mostly to make the exposed API more uniform and self-explanatory.
35
+ It also bundles the updated `sds` library, to sync up with upstream and Redis.
36
+ For code changes see the [Changelog](CHANGELOG.md).
37
+
38
+ _Note: As described below, a few member names have been changed but most applications should be able to upgrade with minor code changes and recompiling._
39
+
40
+ ## IMPORTANT: Breaking changes from `0.14.1` -> `1.0.0`
41
+
42
+ * `redisContext` has two additional members (`free_privdata`, and `privctx`).
43
+ * `redisOptions.timeout` has been renamed to `redisOptions.connect_timeout`, and we've added `redisOptions.command_timeout`.
44
+ * `redisReplyObjectFunctions.createArray` now takes `size_t` instead of `int` for its length parameter.
45
+
46
+ ## IMPORTANT: Breaking changes when upgrading from 0.13.x -> 0.14.x
47
+
48
+ Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now
49
+ protocol errors. This is consistent with the RESP specification. On 32-bit
50
+ platforms, the upper bound is lowered to `SIZE_MAX`.
51
+
52
+ Change `redisReply.len` to `size_t`, as it denotes the the size of a string
53
+
54
+ User code should compare this to `size_t` values as well. If it was used to
55
+ compare to other values, casting might be necessary or can be removed, if
56
+ casting was applied before.
57
+
58
+ ## Upgrading from `<0.9.0`
59
+
60
+ Version 0.9.0 is a major overhaul of hiredis in every aspect. However, upgrading existing
61
+ code using hiredis should not be a big pain. The key thing to keep in mind when
62
+ upgrading is that hiredis >= 0.9.0 uses a `redisContext*` to keep state, in contrast to
63
+ the stateless 0.0.1 that only has a file descriptor to work with.
64
+
65
+ ## Synchronous API
66
+
67
+ To consume the synchronous API, there are only a few function calls that need to be introduced:
68
+
69
+ ```c
70
+ redisContext *redisConnect(const char *ip, int port);
71
+ void *redisCommand(redisContext *c, const char *format, ...);
72
+ void freeReplyObject(void *reply);
73
+ ```
74
+
75
+ ### Connecting
76
+
77
+ The function `redisConnect` is used to create a so-called `redisContext`. The
78
+ context is where Hiredis holds state for a connection. The `redisContext`
79
+ struct has an integer `err` field that is non-zero when the connection is in
80
+ an error state. The field `errstr` will contain a string with a description of
81
+ the error. More information on errors can be found in the **Errors** section.
82
+ After trying to connect to Redis using `redisConnect` you should
83
+ check the `err` field to see if establishing the connection was successful:
84
+ ```c
85
+ redisContext *c = redisConnect("127.0.0.1", 6379);
86
+ if (c == NULL || c->err) {
87
+ if (c) {
88
+ printf("Error: %s\n", c->errstr);
89
+ // handle error
90
+ } else {
91
+ printf("Can't allocate redis context\n");
92
+ }
93
+ }
94
+ ```
95
+
96
+ *Note: A `redisContext` is not thread-safe.*
97
+
98
+ ### Sending commands
99
+
100
+ There are several ways to issue commands to Redis. The first that will be introduced is
101
+ `redisCommand`. This function takes a format similar to printf. In the simplest form,
102
+ it is used like this:
103
+ ```c
104
+ reply = redisCommand(context, "SET foo bar");
105
+ ```
106
+
107
+ The specifier `%s` interpolates a string in the command, and uses `strlen` to
108
+ determine the length of the string:
109
+ ```c
110
+ reply = redisCommand(context, "SET foo %s", value);
111
+ ```
112
+ When you need to pass binary safe strings in a command, the `%b` specifier can be
113
+ used. Together with a pointer to the string, it requires a `size_t` length argument
114
+ of the string:
115
+ ```c
116
+ reply = redisCommand(context, "SET foo %b", value, (size_t) valuelen);
117
+ ```
118
+ Internally, Hiredis splits the command in different arguments and will
119
+ convert it to the protocol used to communicate with Redis.
120
+ One or more spaces separates arguments, so you can use the specifiers
121
+ anywhere in an argument:
122
+ ```c
123
+ reply = redisCommand(context, "SET key:%s %s", myid, value);
124
+ ```
125
+
126
+ ### Using replies
127
+
128
+ The return value of `redisCommand` holds a reply when the command was
129
+ successfully executed. When an error occurs, the return value is `NULL` and
130
+ the `err` field in the context will be set (see section on **Errors**).
131
+ Once an error is returned the context cannot be reused and you should set up
132
+ a new connection.
133
+
134
+ The standard replies that `redisCommand` are of the type `redisReply`. The
135
+ `type` field in the `redisReply` should be used to test what kind of reply
136
+ was received:
137
+
138
+ ### RESP2
139
+
140
+ * **`REDIS_REPLY_STATUS`**:
141
+ * The command replied with a status reply. The status string can be accessed using `reply->str`.
142
+ The length of this string can be accessed using `reply->len`.
143
+
144
+ * **`REDIS_REPLY_ERROR`**:
145
+ * The command replied with an error. The error string can be accessed identical to `REDIS_REPLY_STATUS`.
146
+
147
+ * **`REDIS_REPLY_INTEGER`**:
148
+ * The command replied with an integer. The integer value can be accessed using the
149
+ `reply->integer` field of type `long long`.
150
+
151
+ * **`REDIS_REPLY_NIL`**:
152
+ * The command replied with a **nil** object. There is no data to access.
153
+
154
+ * **`REDIS_REPLY_STRING`**:
155
+ * A bulk (string) reply. The value of the reply can be accessed using `reply->str`.
156
+ The length of this string can be accessed using `reply->len`.
157
+
158
+ * **`REDIS_REPLY_ARRAY`**:
159
+ * A multi bulk reply. The number of elements in the multi bulk reply is stored in
160
+ `reply->elements`. Every element in the multi bulk reply is a `redisReply` object as well
161
+ and can be accessed via `reply->element[..index..]`.
162
+ Redis may reply with nested arrays but this is fully supported.
163
+
164
+ ### RESP3
165
+
166
+ Hiredis also supports every new `RESP3` data type which are as follows. For more information about the protocol see the `RESP3` [specification.](https://github.com/antirez/RESP3/blob/master/spec.md)
167
+
168
+ * **`REDIS_REPLY_DOUBLE`**:
169
+ * The command replied with a double-precision floating point number.
170
+ The value is stored as a string in the `str` member, and can be converted with `strtod` or similar.
171
+
172
+ * **`REDIS_REPLY_BOOL`**:
173
+ * A boolean true/false reply.
174
+ The value is stored in the `integer` member and will be either `0` or `1`.
175
+
176
+ * **`REDIS_REPLY_MAP`**:
177
+ * An array with the added invariant that there will always be an even number of elements.
178
+ The MAP is functionally equivelant to `REDIS_REPLY_ARRAY` except for the previously mentioned invariant.
179
+
180
+ * **`REDIS_REPLY_SET`**:
181
+ * An array response where each entry is unique.
182
+ Like the MAP type, the data is identical to an array response except there are no duplicate values.
183
+
184
+ * **`REDIS_REPLY_PUSH`**:
185
+ * An array that can be generated spontaneously by Redis.
186
+ This array response will always contain at least two subelements. The first contains the type of `PUSH` message (e.g. `message`, or `invalidate`), and the second being a sub-array with the `PUSH` payload itself.
187
+
188
+ * **`REDIS_REPLY_ATTR`**:
189
+ * An array structurally identical to a `MAP` but intended as meta-data about a reply.
190
+ _As of Redis 6.0.6 this reply type is not used in Redis_
191
+
192
+ * **`REDIS_REPLY_BIGNUM`**:
193
+ * A string representing an arbitrarily large signed or unsigned integer value.
194
+ The number will be encoded as a string in the `str` member of `redisReply`.
195
+
196
+ * **`REDIS_REPLY_VERB`**:
197
+ * A verbatim string, intended to be presented to the user without modification.
198
+ The string payload is stored in the `str` memeber, and type data is stored in the `vtype` member (e.g. `txt` for raw text or `md` for markdown).
199
+
200
+ Replies should be freed using the `freeReplyObject()` function.
201
+ Note that this function will take care of freeing sub-reply objects
202
+ contained in arrays and nested arrays, so there is no need for the user to
203
+ free the sub replies (it is actually harmful and will corrupt the memory).
204
+
205
+ **Important:** the current version of hiredis (1.0.0) frees replies when the
206
+ asynchronous API is used. This means you should not call `freeReplyObject` when
207
+ you use this API. The reply is cleaned up by hiredis _after_ the callback
208
+ returns. We may introduce a flag to make this configurable in future versions of the library.
209
+
210
+ ### Cleaning up
211
+
212
+ To disconnect and free the context the following function can be used:
213
+ ```c
214
+ void redisFree(redisContext *c);
215
+ ```
216
+ This function immediately closes the socket and then frees the allocations done in
217
+ creating the context.
218
+
219
+ ### Sending commands (cont'd)
220
+
221
+ Together with `redisCommand`, the function `redisCommandArgv` can be used to issue commands.
222
+ It has the following prototype:
223
+ ```c
224
+ void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
225
+ ```
226
+ It takes the number of arguments `argc`, an array of strings `argv` and the lengths of the
227
+ arguments `argvlen`. For convenience, `argvlen` may be set to `NULL` and the function will
228
+ use `strlen(3)` on every argument to determine its length. Obviously, when any of the arguments
229
+ need to be binary safe, the entire array of lengths `argvlen` should be provided.
230
+
231
+ The return value has the same semantic as `redisCommand`.
232
+
233
+ ### Pipelining
234
+
235
+ To explain how Hiredis supports pipelining in a blocking connection, there needs to be
236
+ understanding of the internal execution flow.
237
+
238
+ When any of the functions in the `redisCommand` family is called, Hiredis first formats the
239
+ command according to the Redis protocol. The formatted command is then put in the output buffer
240
+ of the context. This output buffer is dynamic, so it can hold any number of commands.
241
+ After the command is put in the output buffer, `redisGetReply` is called. This function has the
242
+ following two execution paths:
243
+
244
+ 1. The input buffer is non-empty:
245
+ * Try to parse a single reply from the input buffer and return it
246
+ * If no reply could be parsed, continue at *2*
247
+ 2. The input buffer is empty:
248
+ * Write the **entire** output buffer to the socket
249
+ * Read from the socket until a single reply could be parsed
250
+
251
+ The function `redisGetReply` is exported as part of the Hiredis API and can be used when a reply
252
+ is expected on the socket. To pipeline commands, the only things that needs to be done is
253
+ filling up the output buffer. For this cause, two commands can be used that are identical
254
+ to the `redisCommand` family, apart from not returning a reply:
255
+ ```c
256
+ void redisAppendCommand(redisContext *c, const char *format, ...);
257
+ void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
258
+ ```
259
+ After calling either function one or more times, `redisGetReply` can be used to receive the
260
+ subsequent replies. The return value for this function is either `REDIS_OK` or `REDIS_ERR`, where
261
+ the latter means an error occurred while reading a reply. Just as with the other commands,
262
+ the `err` field in the context can be used to find out what the cause of this error is.
263
+
264
+ The following examples shows a simple pipeline (resulting in only a single call to `write(2)` and
265
+ a single call to `read(2)`):
266
+ ```c
267
+ redisReply *reply;
268
+ redisAppendCommand(context,"SET foo bar");
269
+ redisAppendCommand(context,"GET foo");
270
+ redisGetReply(context,(void *)&reply); // reply for SET
271
+ freeReplyObject(reply);
272
+ redisGetReply(context,(void *)&reply); // reply for GET
273
+ freeReplyObject(reply);
274
+ ```
275
+ This API can also be used to implement a blocking subscriber:
276
+ ```c
277
+ reply = redisCommand(context,"SUBSCRIBE foo");
278
+ freeReplyObject(reply);
279
+ while(redisGetReply(context,(void *)&reply) == REDIS_OK) {
280
+ // consume message
281
+ freeReplyObject(reply);
282
+ }
283
+ ```
284
+ ### Errors
285
+
286
+ When a function call is not successful, depending on the function either `NULL` or `REDIS_ERR` is
287
+ returned. The `err` field inside the context will be non-zero and set to one of the
288
+ following constants:
289
+
290
+ * **`REDIS_ERR_IO`**:
291
+ There was an I/O error while creating the connection, trying to write
292
+ to the socket or read from the socket. If you included `errno.h` in your
293
+ application, you can use the global `errno` variable to find out what is
294
+ wrong.
295
+
296
+ * **`REDIS_ERR_EOF`**:
297
+ The server closed the connection which resulted in an empty read.
298
+
299
+ * **`REDIS_ERR_PROTOCOL`**:
300
+ There was an error while parsing the protocol.
301
+
302
+ * **`REDIS_ERR_OTHER`**:
303
+ Any other error. Currently, it is only used when a specified hostname to connect
304
+ to cannot be resolved.
305
+
306
+ In every case, the `errstr` field in the context will be set to hold a string representation
307
+ of the error.
308
+
309
+ ## Asynchronous API
310
+
311
+ Hiredis comes with an asynchronous API that works easily with any event library.
312
+ Examples are bundled that show using Hiredis with [libev](http://software.schmorp.de/pkg/libev.html)
313
+ and [libevent](http://monkey.org/~provos/libevent/).
314
+
315
+ ### Connecting
316
+
317
+ The function `redisAsyncConnect` can be used to establish a non-blocking connection to
318
+ Redis. It returns a pointer to the newly created `redisAsyncContext` struct. The `err` field
319
+ should be checked after creation to see if there were errors creating the connection.
320
+ Because the connection that will be created is non-blocking, the kernel is not able to
321
+ instantly return if the specified host and port is able to accept a connection.
322
+
323
+ *Note: A `redisAsyncContext` is not thread-safe.*
324
+
325
+ ```c
326
+ redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
327
+ if (c->err) {
328
+ printf("Error: %s\n", c->errstr);
329
+ // handle error
330
+ }
331
+ ```
332
+
333
+ The asynchronous context can hold a disconnect callback function that is called when the
334
+ connection is disconnected (either because of an error or per user request). This function should
335
+ have the following prototype:
336
+ ```c
337
+ void(const redisAsyncContext *c, int status);
338
+ ```
339
+ On a disconnect, the `status` argument is set to `REDIS_OK` when disconnection was initiated by the
340
+ user, or `REDIS_ERR` when the disconnection was caused by an error. When it is `REDIS_ERR`, the `err`
341
+ field in the context can be accessed to find out the cause of the error.
342
+
343
+ The context object is always freed after the disconnect callback fired. When a reconnect is needed,
344
+ the disconnect callback is a good point to do so.
345
+
346
+ Setting the disconnect callback can only be done once per context. For subsequent calls it will
347
+ return `REDIS_ERR`. The function to set the disconnect callback has the following prototype:
348
+ ```c
349
+ int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
350
+ ```
351
+ `ac->data` may be used to pass user data to this callback, the same can be done for redisConnectCallback.
352
+ ### Sending commands and their callbacks
353
+
354
+ In an asynchronous context, commands are automatically pipelined due to the nature of an event loop.
355
+ Therefore, unlike the synchronous API, there is only a single way to send commands.
356
+ Because commands are sent to Redis asynchronously, issuing a command requires a callback function
357
+ that is called when the reply is received. Reply callbacks should have the following prototype:
358
+ ```c
359
+ void(redisAsyncContext *c, void *reply, void *privdata);
360
+ ```
361
+ The `privdata` argument can be used to curry arbitrary data to the callback from the point where
362
+ the command is initially queued for execution.
363
+
364
+ The functions that can be used to issue commands in an asynchronous context are:
365
+ ```c
366
+ int redisAsyncCommand(
367
+ redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
368
+ const char *format, ...);
369
+ int redisAsyncCommandArgv(
370
+ redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
371
+ int argc, const char **argv, const size_t *argvlen);
372
+ ```
373
+ Both functions work like their blocking counterparts. The return value is `REDIS_OK` when the command
374
+ was successfully added to the output buffer and `REDIS_ERR` otherwise. Example: when the connection
375
+ is being disconnected per user-request, no new commands may be added to the output buffer and `REDIS_ERR` is
376
+ returned on calls to the `redisAsyncCommand` family.
377
+
378
+ If the reply for a command with a `NULL` callback is read, it is immediately freed. When the callback
379
+ for a command is non-`NULL`, the memory is freed immediately following the callback: the reply is only
380
+ valid for the duration of the callback.
381
+
382
+ All pending callbacks are called with a `NULL` reply when the context encountered an error.
383
+
384
+ ### Disconnecting
385
+
386
+ An asynchronous connection can be terminated using:
387
+ ```c
388
+ void redisAsyncDisconnect(redisAsyncContext *ac);
389
+ ```
390
+ When this function is called, the connection is **not** immediately terminated. Instead, new
391
+ commands are no longer accepted and the connection is only terminated when all pending commands
392
+ have been written to the socket, their respective replies have been read and their respective
393
+ callbacks have been executed. After this, the disconnection callback is executed with the
394
+ `REDIS_OK` status and the context object is freed.
395
+
396
+ ### Hooking it up to event library *X*
397
+
398
+ There are a few hooks that need to be set on the context object after it is created.
399
+ See the `adapters/` directory for bindings to *libev* and *libevent*.
400
+
401
+ ## Reply parsing API
402
+
403
+ Hiredis comes with a reply parsing API that makes it easy for writing higher
404
+ level language bindings.
405
+
406
+ The reply parsing API consists of the following functions:
407
+ ```c
408
+ redisReader *redisReaderCreate(void);
409
+ void redisReaderFree(redisReader *reader);
410
+ int redisReaderFeed(redisReader *reader, const char *buf, size_t len);
411
+ int redisReaderGetReply(redisReader *reader, void **reply);
412
+ ```
413
+ The same set of functions are used internally by hiredis when creating a
414
+ normal Redis context, the above API just exposes it to the user for a direct
415
+ usage.
416
+
417
+ ### Usage
418
+
419
+ The function `redisReaderCreate` creates a `redisReader` structure that holds a
420
+ buffer with unparsed data and state for the protocol parser.
421
+
422
+ Incoming data -- most likely from a socket -- can be placed in the internal
423
+ buffer of the `redisReader` using `redisReaderFeed`. This function will make a
424
+ copy of the buffer pointed to by `buf` for `len` bytes. This data is parsed
425
+ when `redisReaderGetReply` is called. This function returns an integer status
426
+ and a reply object (as described above) via `void **reply`. The returned status
427
+ can be either `REDIS_OK` or `REDIS_ERR`, where the latter means something went
428
+ wrong (either a protocol error, or an out of memory error).
429
+
430
+ The parser limits the level of nesting for multi bulk payloads to 7. If the
431
+ multi bulk nesting level is higher than this, the parser returns an error.
432
+
433
+ ### Customizing replies
434
+
435
+ The function `redisReaderGetReply` creates `redisReply` and makes the function
436
+ argument `reply` point to the created `redisReply` variable. For instance, if
437
+ the response of type `REDIS_REPLY_STATUS` then the `str` field of `redisReply`
438
+ will hold the status as a vanilla C string. However, the functions that are
439
+ responsible for creating instances of the `redisReply` can be customized by
440
+ setting the `fn` field on the `redisReader` struct. This should be done
441
+ immediately after creating the `redisReader`.
442
+
443
+ For example, [hiredis-rb](https://github.com/pietern/hiredis-rb/blob/master/ext/hiredis_ext/reader.c)
444
+ uses customized reply object functions to create Ruby objects.
445
+
446
+ ### Reader max buffer
447
+
448
+ Both when using the Reader API directly or when using it indirectly via a
449
+ normal Redis context, the redisReader structure uses a buffer in order to
450
+ accumulate data from the server.
451
+ Usually this buffer is destroyed when it is empty and is larger than 16
452
+ KiB in order to avoid wasting memory in unused buffers
453
+
454
+ However when working with very big payloads destroying the buffer may slow
455
+ down performances considerably, so it is possible to modify the max size of
456
+ an idle buffer changing the value of the `maxbuf` field of the reader structure
457
+ to the desired value. The special value of 0 means that there is no maximum
458
+ value for an idle buffer, so the buffer will never get freed.
459
+
460
+ For instance if you have a normal Redis context you can set the maximum idle
461
+ buffer to zero (unlimited) just with:
462
+ ```c
463
+ context->reader->maxbuf = 0;
464
+ ```
465
+ This should be done only in order to maximize performances when working with
466
+ large payloads. The context should be set back to `REDIS_READER_MAX_BUF` again
467
+ as soon as possible in order to prevent allocation of useless memory.
468
+
469
+ ### Reader max array elements
470
+
471
+ By default the hiredis reply parser sets the maximum number of multi-bulk elements
472
+ to 2^32 - 1 or 4,294,967,295 entries. If you need to process multi-bulk replies
473
+ with more than this many elements you can set the value higher or to zero, meaning
474
+ unlimited with:
475
+ ```c
476
+ context->reader->maxelements = 0;
477
+ ```
478
+
479
+ ## SSL/TLS Support
480
+
481
+ ### Building
482
+
483
+ SSL/TLS support is not built by default and requires an explicit flag:
484
+
485
+ make USE_SSL=1
486
+
487
+ This requires OpenSSL development package (e.g. including header files to be
488
+ available.
489
+
490
+ When enabled, SSL/TLS support is built into extra `libhiredis_ssl.a` and
491
+ `libhiredis_ssl.so` static/dynamic libraries. This leaves the original libraries
492
+ unaffected so no additional dependencies are introduced.
493
+
494
+ ### Using it
495
+
496
+ First, you'll need to make sure you include the SSL header file:
497
+
498
+ ```c
499
+ #include "hiredis.h"
500
+ #include "hiredis_ssl.h"
501
+ ```
502
+
503
+ You will also need to link against `libhiredis_ssl`, **in addition** to
504
+ `libhiredis` and add `-lssl -lcrypto` to satisfy its dependencies.
505
+
506
+ Hiredis implements SSL/TLS on top of its normal `redisContext` or
507
+ `redisAsyncContext`, so you will need to establish a connection first and then
508
+ initiate an SSL/TLS handshake.
509
+
510
+ #### Hiredis OpenSSL Wrappers
511
+
512
+ Before Hiredis can negotiate an SSL/TLS connection, it is necessary to
513
+ initialize OpenSSL and create a context. You can do that in two ways:
514
+
515
+ 1. Work directly with the OpenSSL API to initialize the library's global context
516
+ and create `SSL_CTX *` and `SSL *` contexts. With an `SSL *` object you can
517
+ call `redisInitiateSSL()`.
518
+ 2. Work with a set of Hiredis-provided wrappers around OpenSSL, create a
519
+ `redisSSLContext` object to hold configuration and use
520
+ `redisInitiateSSLWithContext()` to initiate the SSL/TLS handshake.
521
+
522
+ ```c
523
+ /* An Hiredis SSL context. It holds SSL configuration and can be reused across
524
+ * many contexts.
525
+ */
526
+ redisSSLContext *ssl;
527
+
528
+ /* An error variable to indicate what went wrong, if the context fails to
529
+ * initialize.
530
+ */
531
+ redisSSLContextError ssl_error;
532
+
533
+ /* Initialize global OpenSSL state.
534
+ *
535
+ * You should call this only once when your app initializes, and only if
536
+ * you don't explicitly or implicitly initialize OpenSSL it elsewhere.
537
+ */
538
+ redisInitOpenSSL();
539
+
540
+ /* Create SSL context */
541
+ ssl = redisCreateSSLContext(
542
+ "cacertbundle.crt", /* File name of trusted CA/ca bundle file, optional */
543
+ "/path/to/certs", /* Path of trusted certificates, optional */
544
+ "client_cert.pem", /* File name of client certificate file, optional */
545
+ "client_key.pem", /* File name of client private key, optional */
546
+ "redis.mydomain.com", /* Server name to request (SNI), optional */
547
+ &ssl_error
548
+ ) != REDIS_OK) {
549
+ printf("SSL error: %s\n", redisSSLContextGetError(ssl_error);
550
+ /* Abort... */
551
+ }
552
+
553
+ /* Create Redis context and establish connection */
554
+ c = redisConnect("localhost", 6443);
555
+ if (c == NULL || c->err) {
556
+ /* Handle error and abort... */
557
+ }
558
+
559
+ /* Negotiate SSL/TLS */
560
+ if (redisInitiateSSLWithContext(c, ssl) != REDIS_OK) {
561
+ /* Handle error, in c->err / c->errstr */
562
+ }
563
+ ```
564
+
565
+ ## RESP3 PUSH replies
566
+ Redis 6.0 introduced PUSH replies with the reply-type `>`. These messages are generated spontaneously and can arrive at any time, so must be handled using callbacks.
567
+
568
+ ### Default behavior
569
+ Hiredis installs handlers on `redisContext` and `redisAsyncContext` by default, which will intercept and free any PUSH replies detected. This means existing code will work as-is after upgrading to Redis 6 and switching to `RESP3`.
570
+
571
+ ### Custom PUSH handler prototypes
572
+ The callback prototypes differ between `redisContext` and `redisAsyncContext`.
573
+
574
+ #### redisContext
575
+ ```c
576
+ void my_push_handler(void *privdata, void *reply) {
577
+ /* Handle the reply */
578
+
579
+ /* Note: We need to free the reply in our custom handler for
580
+ blocking contexts. This lets us keep the reply if
581
+ we want. */
582
+ freeReplyObject(reply);
583
+ }
584
+ ```
585
+
586
+ #### redisAsyncContext
587
+ ```c
588
+ void my_async_push_handler(redisAsyncContext *ac, void *reply) {
589
+ /* Handle the reply */
590
+
591
+ /* Note: Because async hiredis always frees replies, you should
592
+ not call freeReplyObject in an async push callback. */
593
+ }
594
+ ```
595
+
596
+ ### Installing a custom handler
597
+ There are two ways to set your own PUSH handlers.
598
+
599
+ 1. Set `push_cb` or `async_push_cb` in the `redisOptions` struct and connect with `redisConnectWithOptions` or `redisAsyncConnectWithOptions`.
600
+ ```c
601
+ redisOptions = {0};
602
+ REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
603
+ options->push_cb = my_push_handler;
604
+ redisContext *context = redisConnectWithOptions(&options);
605
+ ```
606
+ 2. Call `redisSetPushCallback` or `redisAsyncSetPushCallback` on a connected context.
607
+ ```c
608
+ redisContext *context = redisConnect("127.0.0.1", 6379);
609
+ redisSetPushCallback(context, my_push_handler);
610
+ ```
611
+
612
+ _Note `redisSetPushCallback` and `redisAsyncSetPushCallback` both return any currently configured handler, making it easy to override and then return to the old value._
613
+
614
+ ### Specifying no handler
615
+ If you have a unique use-case where you don't want hiredis to automatically intercept and free PUSH replies, you will want to configure no handler at all. This can be done in two ways.
616
+ 1. Set the `REDIS_OPT_NO_PUSH_AUTOFREE` flag in `redisOptions` and leave the callback function pointer `NULL`.
617
+ ```c
618
+ redisOptions = {0};
619
+ REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
620
+ options->options |= REDIS_OPT_NO_PUSH_AUTOFREE;
621
+ redisContext *context = redisConnectWithOptions(&options);
622
+ ```
623
+ 3. Call `redisSetPushCallback` with `NULL` once connected.
624
+ ```c
625
+ redisContext *context = redisConnect("127.0.0.1", 6379);
626
+ redisSetPushCallback(context, NULL);
627
+ ```
628
+
629
+ _Note: With no handler configured, calls to `redisCommand` may generate more than one reply, so this strategy is only applicable when there's some kind of blocking`redisGetReply()` loop (e.g. `MONITOR` or `SUBSCRIBE` workloads)._
630
+
631
+ ## Allocator injection
632
+
633
+ Hiredis uses a pass-thru structure of function pointers defined in [alloc.h](https://github.com/redis/hiredis/blob/f5d25850/alloc.h#L41) that contain the currently configured allocation and deallocation functions. By default they just point to libc (`malloc`, `calloc`, `realloc`, etc).
634
+
635
+ ### Overriding
636
+
637
+ One can override the allocators like so:
638
+
639
+ ```c
640
+ hiredisAllocFuncs myfuncs = {
641
+ .mallocFn = my_malloc,
642
+ .callocFn = my_calloc,
643
+ .reallocFn = my_realloc,
644
+ .strdupFn = my_strdup,
645
+ .freeFn = my_free,
646
+ };
647
+
648
+ // Override allocators (function returns current allocators if needed)
649
+ hiredisAllocFuncs orig = hiredisSetAllocators(&myfuncs);
650
+ ```
651
+
652
+ To reset the allocators to their default libc function simply call:
653
+
654
+ ```c
655
+ hiredisResetAllocators();
656
+ ```
657
+
658
+ ## AUTHORS
659
+
660
+ Salvatore Sanfilippo (antirez at gmail),\
661
+ Pieter Noordhuis (pcnoordhuis at gmail)\
662
+ Michael Grunder (michael dot grunder at gmail)
663
+
664
+ _Hiredis is released under the BSD license._