Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 231 lines (182 sloc) 4.998 kb
2507fce Nicolas Favre-Felix Added JSON output.
authored
1 #include "cmd.h"
e2f2b36 Nicolas Favre-Felix Added RAW output.
authored
2 #include "server.h"
de5c283 Nicolas Favre-Felix Added IP range restriction.
authored
3 #include "conf.h"
a7bf6f7 Nicolas Favre-Felix ACL refactoring.
authored
4 #include "acl.h"
e2f2b36 Nicolas Favre-Felix Added RAW output.
authored
5
6 #include "formats/json.h"
7 #include "formats/raw.h"
1ad059d Nicolas Favre-Felix Started adding support for a custom content-type in a second key.
authored
8 #include "formats/custom-type.h"
2507fce Nicolas Favre-Felix Added JSON output.
authored
9
10 #include <stdlib.h>
11 #include <string.h>
12 #include <hiredis/hiredis.h>
4448b0f Nicolas Favre-Felix Proper decoding of URL parameters.
authored
13 #include <ctype.h>
2507fce Nicolas Favre-Felix Added JSON output.
authored
14
15 struct cmd *
16 cmd_new(struct evhttp_request *rq, int count) {
17
18 struct cmd *c = calloc(1, sizeof(struct cmd));
19
20 c->rq = rq;
21 c->count = count;
22
1abb414 Nicolas Favre-Felix Final touch to content-type feature.
authored
23 c->argv = calloc(count, sizeof(char*));
24 c->argv_len = calloc(count, sizeof(size_t));
2507fce Nicolas Favre-Felix Added JSON output.
authored
25
26 return c;
27 }
28
29
30 void
31 cmd_free(struct cmd *c) {
32
33 free(c->argv);
34 free(c->argv_len);
35
36 free(c);
37 }
38
7aab776 Nicolas Favre-Felix Cleanup.
authored
39 /**
40 * Detect disconnection of a pub/sub client. We need to clean up the command.
41 */
794a76d Nicolas Favre-Felix Added debug info, trying to find a way to support SUBSCRIBE.
authored
42 void on_http_disconnect(struct evhttp_connection *evcon, void *ctx) {
d8f6460 Nicolas Favre-Felix Pub/sub progress...
authored
43 struct pubsub_client *ps = ctx;
44
45 (void)evcon;
46
117fe91 Nicolas Favre-Felix More HiRedis updates, and JSONP change.
authored
47 if(ps->s->ac->replies.head) {
48 struct cmd *cmd = ps->s->ac->replies.head->privdata;
49 if(cmd) {
50 cmd_free(cmd);
114d6c9 Nicolas Favre-Felix Cleaned up PUB/SUB leaks.
authored
51 }
d8f6460 Nicolas Favre-Felix Pub/sub progress...
authored
52 ps->s->ac->replies.head->privdata = NULL;
53 }
240f05e Nicolas Favre-Felix PUB/SUB seems to work without crashing...
authored
54 redisAsyncFree(ps->s->ac);
d8f6460 Nicolas Favre-Felix Pub/sub progress...
authored
55 free(ps);
794a76d Nicolas Favre-Felix Added debug info, trying to find a way to support SUBSCRIBE.
authored
56 }
57
4448b0f Nicolas Favre-Felix Proper decoding of URL parameters.
authored
58 /* taken from libevent */
59 static char *
60 decode_uri(const char *uri, size_t length, size_t *out_len, int always_decode_plus) {
61 char c;
62 size_t i, j;
63 int in_query = always_decode_plus;
64
65 char *ret = malloc(length);
66
67 for (i = j = 0; i < length; i++) {
68 c = uri[i];
69 if (c == '?') {
70 in_query = 1;
71 } else if (c == '+' && in_query) {
72 c = ' ';
73 } else if (c == '%' && isxdigit((unsigned char)uri[i+1]) &&
74 isxdigit((unsigned char)uri[i+2])) {
75 char tmp[] = { uri[i+1], uri[i+2], '\0' };
76 c = (char)strtol(tmp, NULL, 16);
77 i += 2;
78 }
79 ret[j++] = c;
80 }
81 *out_len = (size_t)j;
82
83 return ret;
84 }
85
86
de5c283 Nicolas Favre-Felix Added IP range restriction.
authored
87 int
e2f2b36 Nicolas Favre-Felix Added RAW output.
authored
88 cmd_run(struct server *s, struct evhttp_request *rq,
9d2beac Nicolas Favre-Felix Added JSONP.
authored
89 const char *uri, size_t uri_len) {
2507fce Nicolas Favre-Felix Added JSON output.
authored
90
9d2beac Nicolas Favre-Felix Added JSONP.
authored
91 char *qmark = strchr(uri, '?');
a3aa1a9 Nicolas Favre-Felix Bugfix in RAW mode, more code doc.
authored
92 char *slash;
e2f2b36 Nicolas Favre-Felix Added RAW output.
authored
93 const char *p;
2507fce Nicolas Favre-Felix Added JSON output.
authored
94 int cmd_len;
4448b0f Nicolas Favre-Felix Proper decoding of URL parameters.
authored
95 int param_count = 0, cur_param = 1, i;
2507fce Nicolas Favre-Felix Added JSON output.
authored
96
97 struct cmd *cmd;
1ea7cd0 Nicolas Favre-Felix Special GET formatter for key + content-type key.
authored
98
99 formatting_fun f_format;
2507fce Nicolas Favre-Felix Added JSON output.
authored
100
101 /* count arguments */
9d2beac Nicolas Favre-Felix Added JSONP.
authored
102 if(qmark) {
103 uri_len = qmark - uri;
104 }
2507fce Nicolas Favre-Felix Added JSON output.
authored
105 for(p = uri; p && p < uri + uri_len; param_count++) {
106 p = strchr(p+1, '/');
107 }
108
109 cmd = cmd_new(rq, param_count);
110
469e516 Nicolas Favre-Felix Removed content-type in another key, added suffixes instead.
authored
111 /* parse URI parameters */
112 evhttp_parse_query(uri, &cmd->uri_params);
113
114 /* get output formatting function */
115 uri_len = cmd_read_params(cmd, uri, uri_len, &f_format);
116
117 /* check if we only have one command or more. */
a3aa1a9 Nicolas Favre-Felix Bugfix in RAW mode, more code doc.
authored
118 slash = memchr(uri, '/', uri_len);
2507fce Nicolas Favre-Felix Added JSON output.
authored
119 if(slash) {
120 cmd_len = slash - uri;
121 } else {
122 cmd_len = uri_len;
123 }
124
125 /* there is always a first parameter, it's the command name */
126 cmd->argv[0] = uri;
127 cmd->argv_len[0] = cmd_len;
128
2f5454c Nicolas Favre-Felix Merge branch 'master' into pubsub
authored
129
de5c283 Nicolas Favre-Felix Added IP range restriction.
authored
130 /* check that the client is able to run this command */
a7bf6f7 Nicolas Favre-Felix ACL refactoring.
authored
131 if(!acl_allow_command(cmd, s->cfg, rq)) {
de5c283 Nicolas Favre-Felix Added IP range restriction.
authored
132 return -1;
133 }
134
2c980a2 Nicolas Favre-Felix First try.
authored
135 /* check if we have to split the connection */
4676cfe Nicolas Favre-Felix Refactoring.
authored
136 if(cmd_is_subscribe(cmd)) {
d8f6460 Nicolas Favre-Felix Pub/sub progress...
authored
137 struct pubsub_client *ps;
138 ps = calloc(1, sizeof(struct pubsub_client));
139 ps->s = s = server_copy(s);
140
141 ps->rq = rq;
142
143 evhttp_connection_set_closecb(rq->evcon, on_http_disconnect, ps);
2c980a2 Nicolas Favre-Felix First try.
authored
144 }
145
a3aa1a9 Nicolas Favre-Felix Bugfix in RAW mode, more code doc.
authored
146 /* no args (e.g. INFO command) */
2507fce Nicolas Favre-Felix Added JSON output.
authored
147 if(!slash) {
1ea7cd0 Nicolas Favre-Felix Special GET formatter for key + content-type key.
authored
148 redisAsyncCommandArgv(s->ac, f_format, cmd, 1, cmd->argv, cmd->argv_len);
de5c283 Nicolas Favre-Felix Added IP range restriction.
authored
149 return 0;
2507fce Nicolas Favre-Felix Added JSON output.
authored
150 }
151 p = slash + 1;
152 while(p < uri + uri_len) {
153
154 const char *arg = p;
155 int arg_len;
156 char *next = strchr(arg, '/');
5ca45a5 Nicolas Favre-Felix Working custom handler.
authored
157 if(!next || next > uri + uri_len) { /* last argument */
158 p = uri + uri_len;
159 arg_len = p - arg;
160 } else { /* found a slash */
2507fce Nicolas Favre-Felix Added JSON output.
authored
161 arg_len = next - arg;
162 p = next + 1;
163 }
164
165 /* record argument */
4448b0f Nicolas Favre-Felix Proper decoding of URL parameters.
authored
166 cmd->argv[cur_param] = decode_uri(arg, arg_len, &cmd->argv_len[cur_param], 1);
2507fce Nicolas Favre-Felix Added JSON output.
authored
167 cur_param++;
168 }
169
a3aa1a9 Nicolas Favre-Felix Bugfix in RAW mode, more code doc.
authored
170 /* push command to Redis. */
1ea7cd0 Nicolas Favre-Felix Special GET formatter for key + content-type key.
authored
171 redisAsyncCommandArgv(s->ac, f_format, cmd, cmd->count, cmd->argv, cmd->argv_len);
1ad059d Nicolas Favre-Felix Started adding support for a custom content-type in a second key.
authored
172
1abb414 Nicolas Favre-Felix Final touch to content-type feature.
authored
173 for(i = 1; i < cmd->count; ++i) {
4448b0f Nicolas Favre-Felix Proper decoding of URL parameters.
authored
174 free((char*)cmd->argv[i]);
175 }
176
de5c283 Nicolas Favre-Felix Added IP range restriction.
authored
177 return 0;
2507fce Nicolas Favre-Felix Added JSON output.
authored
178 }
179
a3aa1a9 Nicolas Favre-Felix Bugfix in RAW mode, more code doc.
authored
180 /**
181 * Return 2 functions, one to format the reply and
182 * one to transform the command before processing it.
183 */
469e516 Nicolas Favre-Felix Removed content-type in another key, added suffixes instead.
authored
184 int
185 cmd_read_params(struct cmd *cmd, const char *uri, size_t uri_len, formatting_fun *f_format) {
186
187 const char *ext;
188 int ext_len = -1;
189 unsigned int i;
e2f2b36 Nicolas Favre-Felix Added RAW output.
authored
190
469e516 Nicolas Favre-Felix Removed content-type in another key, added suffixes instead.
authored
191 struct reply_format funs[] = {
192 {.s = "json", .sz = 4, .f = json_reply, .ct = "application/json"},
193 {.s = "raw", .sz = 3, .f = raw_reply, .ct = "binary/octet-stream"},
194 {.s = "txt", .sz = 3, .f = custom_type_reply, .ct = "text/plain"},
195 {.s = "html", .sz = 4, .f = custom_type_reply, .ct = "text/html"},
196 {.s = "png", .sz = 3, .f = custom_type_reply, .ct = "image/png"},
197 };
e2f2b36 Nicolas Favre-Felix Added RAW output.
authored
198
1ea7cd0 Nicolas Favre-Felix Special GET formatter for key + content-type key.
authored
199 /* defaults */
200 *f_format = json_reply;
469e516 Nicolas Favre-Felix Removed content-type in another key, added suffixes instead.
authored
201
202 /* find extension */
203 for(ext = uri + uri_len - 1; ext != uri && *ext != '/'; --ext) {
204 if(*ext == '.') {
205 ext++;
206 ext_len = uri + uri_len - ext;
e2f2b36 Nicolas Favre-Felix Added RAW output.
authored
207 break;
208 }
209 }
469e516 Nicolas Favre-Felix Removed content-type in another key, added suffixes instead.
authored
210 if(!ext_len) return uri_len;
211
212 /* find function for the given extension */
213 for(i = 0; i < sizeof(funs)/sizeof(funs[0]); ++i) {
214 if(ext_len == (int)funs[i].sz && strncmp(ext, funs[i].s, ext_len) == 0) {
215 *f_format = funs[i].f;
216 cmd->mime = funs[i].ct;
217 }
218 }
219 return uri_len - ext_len - 1;
e2f2b36 Nicolas Favre-Felix Added RAW output.
authored
220 }
4676cfe Nicolas Favre-Felix Refactoring.
authored
221
222 int
223 cmd_is_subscribe(struct cmd *cmd) {
224
225 if(strncasecmp(cmd->argv[0], "SUBSCRIBE", cmd->argv_len[0]) == 0 ||
226 strncasecmp(cmd->argv[0], "PSUBSCRIBE", cmd->argv_len[0]) == 0) {
227 return 1;
228 }
229 return 0;
230 }
Something went wrong with that request. Please try again.