Skip to content
This repository
Newer
Older
100644 304 lines (246 sloc) 7.126 kb
2507fcee »
2010-12-21 Added JSON output.
1 #include "cmd.h"
de5c2839 »
2010-12-27 Added IP range restriction.
2 #include "conf.h"
a7bf6f76 »
2011-01-01 ACL refactoring.
3 #include "acl.h"
7cfb80d4 »
2011-01-24 Add client.{c,h}. Needs a lot more refactoring.
4 #include "client.h"
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
5 #include "pool.h"
6 #include "worker.h"
7 #include "http.h"
8 #include "server.h"
e2f2b365 »
2010-12-26 Added RAW output.
9
10 #include "formats/json.h"
e4d27387 »
2011-02-01 BSON support.
11 #include "formats/bson.h"
e2f2b365 »
2010-12-26 Added RAW output.
12 #include "formats/raw.h"
1ad059d7 »
2011-01-03 Started adding support for a custom content-type in a second key.
13 #include "formats/custom-type.h"
2507fcee »
2010-12-21 Added JSON output.
14
15 #include <stdlib.h>
16 #include <string.h>
17 #include <hiredis/hiredis.h>
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
18 #include <hiredis/async.h>
4448b0fa »
2011-01-03 Proper decoding of URL parameters.
19 #include <ctype.h>
2507fcee »
2010-12-21 Added JSON output.
20
21 struct cmd *
a298d3c1 »
2011-01-25 Better client/cmd relationship.
22 cmd_new(int count) {
2507fcee »
2010-12-21 Added JSON output.
23
24 struct cmd *c = calloc(1, sizeof(struct cmd));
25
26 c->count = count;
27
1abb4149 »
2011-01-03 Final touch to content-type feature.
28 c->argv = calloc(count, sizeof(char*));
29 c->argv_len = calloc(count, sizeof(size_t));
2507fcee »
2010-12-21 Added JSON output.
30
31 return c;
32 }
33
34
35 void
36 cmd_free(struct cmd *c) {
37
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
38 int i;
a298d3c1 »
2011-01-25 Better client/cmd relationship.
39 if(!c) return;
40
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
41 for(i = 0; i < c->count; ++i) {
42 free((char*)c->argv[i]);
43 }
2507fcee »
2010-12-21 Added JSON output.
44 free(c->argv);
45 free(c->argv_len);
46
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
47 free(c->jsonp);
48 free(c->if_none_match);
102f9fcd »
2011-01-05 Started adding Accept support.
49 if(c->mime_free) free(c->mime);
50
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
51
2507fcee »
2010-12-21 Added JSON output.
52 free(c);
53 }
54
4448b0fa »
2011-01-03 Proper decoding of URL parameters.
55 /* taken from libevent */
56 static char *
57 decode_uri(const char *uri, size_t length, size_t *out_len, int always_decode_plus) {
58 char c;
59 size_t i, j;
60 int in_query = always_decode_plus;
61
62 char *ret = malloc(length);
63
64 for (i = j = 0; i < length; i++) {
65 c = uri[i];
66 if (c == '?') {
67 in_query = 1;
68 } else if (c == '+' && in_query) {
69 c = ' ';
70 } else if (c == '%' && isxdigit((unsigned char)uri[i+1]) &&
71 isxdigit((unsigned char)uri[i+2])) {
72 char tmp[] = { uri[i+1], uri[i+2], '\0' };
73 c = (char)strtol(tmp, NULL, 16);
74 i += 2;
75 }
76 ret[j++] = c;
77 }
78 *out_len = (size_t)j;
79
80 return ret;
81 }
82
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
83 /* setup headers */
84 static void
85 cmd_setup(struct cmd *cmd, struct http_client *client) {
86
87 int i;
88 cmd->keep_alive = client->keep_alive;
89
90 for(i = 0; i < client->header_count; ++i) {
91 if(strcasecmp(client->headers[i].key, "If-None-Match") == 0) {
92 cmd->if_none_match = calloc(1+client->headers[i].val_sz, 1);
93 memcpy(cmd->if_none_match, client->headers[i].val,
94 client->headers[i].val_sz);
95 } else if(strcasecmp(client->headers[i].key, "Connection") == 0 &&
96 strcasecmp(client->headers[i].val, "Keep-Alive") == 0) {
97 cmd->keep_alive = 1;
98 }
99 }
100
101 if(client->type) { /* transfer pointer ownership */
102 cmd->mime = client->type;
103 cmd->mime_free = 1;
104 client->type = NULL;
105 }
106
107 if(client->jsonp) { /* transfer pointer ownership */
108 cmd->jsonp = client->jsonp;
109 client->jsonp = NULL;
110 }
111 }
112
4448b0fa »
2011-01-03 Proper decoding of URL parameters.
113
de5c2839 »
2010-12-27 Added IP range restriction.
114 int
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
115 cmd_run(struct worker *w, struct http_client *client,
89bb00f5 »
2011-01-22 Start sending HTTP replies.
116 const char *uri, size_t uri_len,
117 const char *body, size_t body_len) {
2507fcee »
2010-12-21 Added JSON output.
118
89bb00f5 »
2011-01-22 Start sending HTTP replies.
119 char *qmark = memchr(uri, '?', uri_len);
a3aa1a92 »
2011-01-03 Bugfix in RAW mode, more code doc.
120 char *slash;
e2f2b365 »
2010-12-26 Added RAW output.
121 const char *p;
2507fcee »
2010-12-21 Added JSON output.
122 int cmd_len;
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
123 int param_count = 0, cur_param = 1;
2507fcee »
2010-12-21 Added JSON output.
124
125 struct cmd *cmd;
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
126 redisAsyncContext *ac = NULL;
1ea7cd07 »
2011-01-03 Special GET formatter for key + content-type key.
127 formatting_fun f_format;
2507fcee »
2010-12-21 Added JSON output.
128
129 /* count arguments */
9d2beace »
2010-12-22 Added JSONP.
130 if(qmark) {
131 uri_len = qmark - uri;
132 }
2507fcee »
2010-12-21 Added JSON output.
133 for(p = uri; p && p < uri + uri_len; param_count++) {
89bb00f5 »
2011-01-22 Start sending HTTP replies.
134 p = memchr(p+1, '/', uri_len - (p+1-uri));
2507fcee »
2010-12-21 Added JSON output.
135 }
136
a3ee623c »
2011-01-09 File uploads using HTTP PUT.
137 if(body && body_len) { /* PUT request */
138 param_count++;
139 }
70d2e070 »
2011-01-26 Fix memory access on empty commands.
140 if(param_count == 0) {
141 return -1;
142 }
a3ee623c »
2011-01-09 File uploads using HTTP PUT.
143
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
144 cmd = cmd_new(param_count);
145 cmd->fd = client->fd;
2507fcee »
2010-12-21 Added JSON output.
146
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
147 /* get output formatting function */
bbec5c65 »
2011-01-22 Bugfix, restored forced content-type.
148 uri_len = cmd_select_format(client, cmd, uri, uri_len, &f_format);
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
149
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
150 /* add HTTP info */
151 cmd_setup(cmd, client);
152
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
153 /* check if we only have one command or more. */
a3aa1a92 »
2011-01-03 Bugfix in RAW mode, more code doc.
154 slash = memchr(uri, '/', uri_len);
2507fcee »
2010-12-21 Added JSON output.
155 if(slash) {
156 cmd_len = slash - uri;
157 } else {
158 cmd_len = uri_len;
159 }
160
161 /* there is always a first parameter, it's the command name */
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
162 cmd->argv[0] = malloc(cmd_len);
163 memcpy(cmd->argv[0], uri, cmd_len);
2507fcee »
2010-12-21 Added JSON output.
164 cmd->argv_len[0] = cmd_len;
165
9ffc5197 »
2011-01-22 Fix ACLs
166 /* check that the client is able to run this command */
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
167 if(!acl_allow_command(cmd, w->s->cfg, client)) {
de5c2839 »
2010-12-27 Added IP range restriction.
168 return -1;
169 }
170
6026811c »
2011-01-23 Fix pub/sub. Valgrind is happy.
171 /* check if we have to split the connection */
4676cfeb »
2010-12-29 Refactoring.
172 if(cmd_is_subscribe(cmd)) {
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
173 ac = (redisAsyncContext*)pool_connect(w->pool, 0);
2c980a21 »
2010-12-26 First try.
174 }
175
a3aa1a92 »
2011-01-03 Bugfix in RAW mode, more code doc.
176 /* no args (e.g. INFO command) */
2507fcee »
2010-12-21 Added JSON output.
177 if(!slash) {
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
178 ac = (redisAsyncContext*)pool_get_context(w->pool);
179 redisAsyncCommandArgv(ac, f_format, cmd, 1,
180 (const char **)cmd->argv, cmd->argv_len);
de5c2839 »
2010-12-27 Added IP range restriction.
181 return 0;
2507fcee »
2010-12-21 Added JSON output.
182 }
183 p = slash + 1;
184 while(p < uri + uri_len) {
185
186 const char *arg = p;
187 int arg_len;
d9d85ca1 »
2011-01-22 Fix realloc bug.
188 char *next = memchr(arg, '/', uri_len - (arg-uri));
5ca45a54 »
2011-01-03 Working custom handler.
189 if(!next || next > uri + uri_len) { /* last argument */
190 p = uri + uri_len;
191 arg_len = p - arg;
192 } else { /* found a slash */
2507fcee »
2010-12-21 Added JSON output.
193 arg_len = next - arg;
194 p = next + 1;
195 }
196
197 /* record argument */
4448b0fa »
2011-01-03 Proper decoding of URL parameters.
198 cmd->argv[cur_param] = decode_uri(arg, arg_len, &cmd->argv_len[cur_param], 1);
2507fcee »
2010-12-21 Added JSON output.
199 cur_param++;
200 }
201
a3ee623c »
2011-01-09 File uploads using HTTP PUT.
202 if(body && body_len) { /* PUT request */
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
203 cmd->argv[cur_param] = malloc(body_len);
204 memcpy(cmd->argv[cur_param], body, body_len);
a3ee623c »
2011-01-09 File uploads using HTTP PUT.
205 cmd->argv_len[cur_param] = body_len;
206 }
207
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
208 /* send it off! */
209 if(!ac) {
210 ac = (redisAsyncContext*)pool_get_context(w->pool);
4448b0fa »
2011-01-03 Proper decoding of URL parameters.
211 }
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
212 cmd_send(ac, f_format, cmd);
4448b0fa »
2011-01-03 Proper decoding of URL parameters.
213
de5c2839 »
2010-12-27 Added IP range restriction.
214 return 0;
2507fcee »
2010-12-21 Added JSON output.
215 }
216
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
217 void
218 cmd_send(redisAsyncContext *ac, formatting_fun f_format, struct cmd *cmd) {
219 redisAsyncCommandArgv(ac, f_format, cmd, cmd->count,
220 (const char **)cmd->argv, cmd->argv_len);
221 }
6e3c4240 »
2011-01-04 Cleanup.
222
a3aa1a92 »
2011-01-03 Bugfix in RAW mode, more code doc.
223 /**
6e3c4240 »
2011-01-04 Cleanup.
224 * Select Content-Type and processing function.
a3aa1a92 »
2011-01-03 Bugfix in RAW mode, more code doc.
225 */
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
226 int
bbec5c65 »
2011-01-22 Bugfix, restored forced content-type.
227 cmd_select_format(struct http_client *client, struct cmd *cmd,
228 const char *uri, size_t uri_len, formatting_fun *f_format) {
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
229
71bc9e39 »
2011-01-05 Added a few content types, added support for ?type.
230 const char *ext;
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
231 int ext_len = -1;
232 unsigned int i;
e2f2b365 »
2010-12-26 Added RAW output.
233
6e3c4240 »
2011-01-04 Cleanup.
234 /* those are the available reply formats */
235 struct reply_format {
236 const char *s;
237 size_t sz;
238 formatting_fun f;
239 const char *ct;
240 };
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
241 struct reply_format funs[] = {
242 {.s = "json", .sz = 4, .f = json_reply, .ct = "application/json"},
243 {.s = "raw", .sz = 3, .f = raw_reply, .ct = "binary/octet-stream"},
e4d27387 »
2011-02-01 BSON support.
244 {.s = "bson", .sz = 4, .f = bson_reply, .ct = "application/bson"},
4abc4fc4 »
2011-01-09 Support for .bin as binary/octet-stream
245
246 {.s = "bin", .sz = 3, .f = custom_type_reply, .ct = "binary/octet-stream"},
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
247 {.s = "txt", .sz = 3, .f = custom_type_reply, .ct = "text/plain"},
248 {.s = "html", .sz = 4, .f = custom_type_reply, .ct = "text/html"},
71bc9e39 »
2011-01-05 Added a few content types, added support for ?type.
249 {.s = "xhtml", .sz = 5, .f = custom_type_reply, .ct = "application/xhtml+xml"},
250 {.s = "xml", .sz = 3, .f = custom_type_reply, .ct = "text/xml"},
251
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
252 {.s = "png", .sz = 3, .f = custom_type_reply, .ct = "image/png"},
71bc9e39 »
2011-01-05 Added a few content types, added support for ?type.
253 {.s = "jpg", .sz = 3, .f = custom_type_reply, .ct = "image/jpeg"},
254 {.s = "jpeg", .sz = 4, .f = custom_type_reply, .ct = "image/jpeg"},
1b6f36bd »
2011-03-02 Added Content-Type for JS and CSS files.
255
256 {.s = "js", .sz = 2, .f = custom_type_reply, .ct = "application/javascript"},
257 {.s = "css", .sz = 3, .f = custom_type_reply, .ct = "text/css"},
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
258 };
e2f2b365 »
2010-12-26 Added RAW output.
259
6e3c4240 »
2011-01-04 Cleanup.
260 /* default */
1ea7cd07 »
2011-01-03 Special GET formatter for key + content-type key.
261 *f_format = json_reply;
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
262
263 /* find extension */
264 for(ext = uri + uri_len - 1; ext != uri && *ext != '/'; --ext) {
265 if(*ext == '.') {
266 ext++;
267 ext_len = uri + uri_len - ext;
e2f2b365 »
2010-12-26 Added RAW output.
268 break;
269 }
270 }
6e3c4240 »
2011-01-04 Cleanup.
271 if(!ext_len) return uri_len; /* nothing found */
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
272
273 /* find function for the given extension */
274 for(i = 0; i < sizeof(funs)/sizeof(funs[0]); ++i) {
275 if(ext_len == (int)funs[i].sz && strncmp(ext, funs[i].s, ext_len) == 0) {
102f9fcd »
2011-01-05 Started adding Accept support.
276
277 if(cmd->mime_free) free(cmd->mime);
278 cmd->mime = (char*)funs[i].ct;
279 cmd->mime_free = 0;
280
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
281 *f_format = funs[i].f;
282 }
283 }
71bc9e39 »
2011-01-05 Added a few content types, added support for ?type.
284
6026811c »
2011-01-23 Fix pub/sub. Valgrind is happy.
285 /* the user can force it with ?type=some/thing */
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
286 if(client->type) {
bbec5c65 »
2011-01-22 Bugfix, restored forced content-type.
287 *f_format = custom_type_reply;
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
288 cmd->mime = strdup(client->type);
bbec5c65 »
2011-01-22 Bugfix, restored forced content-type.
289 cmd->mime_free = 1;
71bc9e39 »
2011-01-05 Added a few content types, added support for ?type.
290 }
bbec5c65 »
2011-01-22 Bugfix, restored forced content-type.
291
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
292 return uri_len - ext_len - 1;
e2f2b365 »
2010-12-26 Added RAW output.
293 }
4676cfeb »
2010-12-29 Refactoring.
294
295 int
296 cmd_is_subscribe(struct cmd *cmd) {
297
9378544d »
2011-01-26 Fix subscribe leak.
298 if(cmd->count >= 1 &&
981fd54a »
2011-01-22 Fix Keep-Alive.
299 (strncasecmp(cmd->argv[0], "SUBSCRIBE", cmd->argv_len[0]) == 0 ||
300 strncasecmp(cmd->argv[0], "PSUBSCRIBE", cmd->argv_len[0]) == 0)) {
4676cfeb »
2010-12-29 Refactoring.
301 return 1;
302 }
303 return 0;
304 }
Something went wrong with that request. Please try again.