/formats/raw.c

http://github.com/nicolasff/webdis · C · 192 lines · 140 code · 39 blank · 13 comment · 16 complexity · 3a707aba8ba1f20ffc1551f9cbdbc612 MD5 · raw file

  1. #include "raw.h"
  2. #include "common.h"
  3. #include "http.h"
  4. #include "client.h"
  5. #include "cmd.h"
  6. #include <string.h>
  7. #include <hiredis/hiredis.h>
  8. #include <hiredis/async.h>
  9. static char *
  10. raw_wrap(const redisReply *r, size_t *sz);
  11. void
  12. raw_reply(redisAsyncContext *c, void *r, void *privdata) {
  13. redisReply *reply = r;
  14. struct cmd *cmd = privdata;
  15. char *raw_out;
  16. size_t sz;
  17. (void)c;
  18. if (reply == NULL) { /* broken Redis link */
  19. format_send_error(cmd, 503, "Service Unavailable");
  20. return;
  21. }
  22. raw_out = raw_wrap(r, &sz);
  23. /* send reply */
  24. format_send_reply(cmd, raw_out, sz, "binary/octet-stream");
  25. /* cleanup */
  26. free(raw_out);
  27. }
  28. /* extract Redis protocol string from WebSocket frame and fill struct cmd. */
  29. struct cmd *
  30. raw_ws_extract(struct http_client *c, const char *p, size_t sz) {
  31. struct cmd *cmd = NULL;
  32. void *reader = NULL;
  33. redisReply *reply = NULL;
  34. void **reply_ptr = (void**)&reply;
  35. unsigned int i;
  36. (void)c;
  37. /* create protocol reader */
  38. reader = redisReaderCreate();
  39. /* add data */
  40. redisReaderFeed(reader, (char*)p, sz);
  41. /* parse data into reply object */
  42. if(redisReaderGetReply(reader, reply_ptr) == REDIS_ERR) {
  43. goto end;
  44. }
  45. /* add data from reply object to cmd struct */
  46. if(reply->type != REDIS_REPLY_ARRAY) {
  47. goto end;
  48. }
  49. /* create cmd object */
  50. cmd = cmd_new(reply->elements);
  51. for(i = 0; i < reply->elements; ++i) {
  52. redisReply *ri = reply->element[i];
  53. switch(ri->type) {
  54. case REDIS_REPLY_STRING:
  55. cmd->argv_len[i] = ri->len;
  56. cmd->argv[i] = calloc(cmd->argv_len[i] + 1, 1);
  57. memcpy(cmd->argv[i], ri->str, ri->len);
  58. break;
  59. case REDIS_REPLY_INTEGER:
  60. cmd->argv_len[i] = integer_length(ri->integer);
  61. cmd->argv[i] = calloc(cmd->argv_len[i] + 1, 1);
  62. sprintf(cmd->argv[i], "%lld", ri->integer);
  63. break;
  64. default:
  65. cmd_free(cmd);
  66. cmd = NULL;
  67. goto end;
  68. }
  69. }
  70. end:
  71. /* free reader */
  72. if(reader) redisReaderFree(reader);
  73. /* free reply */
  74. if(reply) freeReplyObject(reply);
  75. return cmd;
  76. }
  77. static char *
  78. raw_array(const redisReply *r, size_t *sz) {
  79. unsigned int i;
  80. char *ret, *p;
  81. /* compute size */
  82. *sz = 0;
  83. *sz += 1 + integer_length(r->elements) + 2;
  84. for(i = 0; i < r->elements; ++i) {
  85. redisReply *e = r->element[i];
  86. switch(e->type) {
  87. case REDIS_REPLY_STRING:
  88. *sz += 1 + integer_length(e->len) + 2
  89. + e->len + 2;
  90. break;
  91. case REDIS_REPLY_INTEGER:
  92. *sz += 1 + integer_length(integer_length(e->integer)) + 2
  93. + integer_length(e->integer) + 2;
  94. break;
  95. }
  96. }
  97. /* allocate */
  98. p = ret = malloc(1+*sz);
  99. p += sprintf(p, "*%zd\r\n", r->elements);
  100. /* copy */
  101. for(i = 0; i < r->elements; ++i) {
  102. redisReply *e = r->element[i];
  103. switch(e->type) {
  104. case REDIS_REPLY_STRING:
  105. p += sprintf(p, "$%d\r\n", e->len);
  106. memcpy(p, e->str, e->len);
  107. p += e->len;
  108. *p = '\r';
  109. p++;
  110. *p = '\n';
  111. p++;
  112. break;
  113. case REDIS_REPLY_INTEGER:
  114. p += sprintf(p, "$%d\r\n%lld\r\n",
  115. integer_length(e->integer), e->integer);
  116. break;
  117. }
  118. }
  119. return ret;
  120. }
  121. static char *
  122. raw_wrap(const redisReply *r, size_t *sz) {
  123. char *ret, *p;
  124. switch(r->type) {
  125. case REDIS_REPLY_STATUS:
  126. case REDIS_REPLY_ERROR:
  127. *sz = 3 + r->len;
  128. ret = malloc(*sz);
  129. ret[0] = (r->type == REDIS_REPLY_STATUS?'+':'-');
  130. memcpy(ret+1, r->str, *sz-3);
  131. memcpy(ret+*sz - 2, "\r\n", 2);
  132. return ret;
  133. case REDIS_REPLY_STRING:
  134. *sz = 1 + integer_length(r->len) + 2 + r->len + 2;
  135. p = ret = malloc(*sz);
  136. p += sprintf(p, "$%d\r\n", r->len);
  137. memcpy(p, r->str, *sz - 2 - (p-ret));
  138. memcpy(ret + *sz - 2, "\r\n", 2);
  139. return ret;
  140. case REDIS_REPLY_INTEGER:
  141. *sz = 3 + integer_length(r->integer);
  142. ret = malloc(4+*sz);
  143. sprintf(ret, ":%lld\r\n", r->integer);
  144. return ret;
  145. case REDIS_REPLY_ARRAY:
  146. return raw_array(r, sz);
  147. default:
  148. *sz = 5;
  149. ret = malloc(*sz);
  150. memcpy(ret, "$-1\r\n", 5);
  151. return ret;
  152. }
  153. }