PageRenderTime 50ms CodeModel.GetById 25ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 1ms

/formats/raw.c

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