Skip to content
This repository
Newer
Older
100644 317 lines (258 sloc) 7.455 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 */
239c9004 »
2011-04-08 HTTP version in reply.
84 void
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
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 }
239c9004 »
2011-04-08 HTTP version in reply.
111
112 cmd->fd = client->fd;
113 cmd->http_version = client->http_version;
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
114 }
115
4448b0fa »
2011-01-03 Proper decoding of URL parameters.
116
bf2f5841 »
2011-04-09 Fixed 503 responses when Redis is down.
117 cmd_response_t
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
118 cmd_run(struct worker *w, struct http_client *client,
89bb00f5 »
2011-01-22 Start sending HTTP replies.
119 const char *uri, size_t uri_len,
120 const char *body, size_t body_len) {
2507fcee »
2010-12-21 Added JSON output.
121
89bb00f5 »
2011-01-22 Start sending HTTP replies.
122 char *qmark = memchr(uri, '?', uri_len);
a3aa1a92 »
2011-01-03 Bugfix in RAW mode, more code doc.
123 char *slash;
e2f2b365 »
2010-12-26 Added RAW output.
124 const char *p;
2507fcee »
2010-12-21 Added JSON output.
125 int cmd_len;
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
126 int param_count = 0, cur_param = 1;
2507fcee »
2010-12-21 Added JSON output.
127
128 struct cmd *cmd;
1ea7cd07 »
2011-01-03 Special GET formatter for key + content-type key.
129 formatting_fun f_format;
2507fcee »
2010-12-21 Added JSON output.
130
131 /* count arguments */
9d2beace »
2010-12-22 Added JSONP.
132 if(qmark) {
133 uri_len = qmark - uri;
134 }
2507fcee »
2010-12-21 Added JSON output.
135 for(p = uri; p && p < uri + uri_len; param_count++) {
89bb00f5 »
2011-01-22 Start sending HTTP replies.
136 p = memchr(p+1, '/', uri_len - (p+1-uri));
2507fcee »
2010-12-21 Added JSON output.
137 }
138
a3ee623c »
2011-01-09 File uploads using HTTP PUT.
139 if(body && body_len) { /* PUT request */
140 param_count++;
141 }
70d2e070 »
2011-01-26 Fix memory access on empty commands.
142 if(param_count == 0) {
bf2f5841 »
2011-04-09 Fixed 503 responses when Redis is down.
143 return CMD_PARAM_ERROR;
70d2e070 »
2011-01-26 Fix memory access on empty commands.
144 }
a3ee623c »
2011-01-09 File uploads using HTTP PUT.
145
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
146 cmd = cmd_new(param_count);
147 cmd->fd = client->fd;
2507fcee »
2010-12-21 Added JSON output.
148
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
149 /* get output formatting function */
bbec5c65 »
2011-01-22 Bugfix, restored forced content-type.
150 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.
151
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
152 /* add HTTP info */
153 cmd_setup(cmd, client);
154
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
155 /* check if we only have one command or more. */
a3aa1a92 »
2011-01-03 Bugfix in RAW mode, more code doc.
156 slash = memchr(uri, '/', uri_len);
2507fcee »
2010-12-21 Added JSON output.
157 if(slash) {
158 cmd_len = slash - uri;
159 } else {
160 cmd_len = uri_len;
161 }
162
163 /* there is always a first parameter, it's the command name */
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
164 cmd->argv[0] = malloc(cmd_len);
165 memcpy(cmd->argv[0], uri, cmd_len);
2507fcee »
2010-12-21 Added JSON output.
166 cmd->argv_len[0] = cmd_len;
167
9ffc5197 »
2011-01-22 Fix ACLs
168 /* check that the client is able to run this command */
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
169 if(!acl_allow_command(cmd, w->s->cfg, client)) {
513982d8 »
2011-04-12 Added asynchronous reconnect, fixed memory leak.
170 cmd_free(cmd);
bf2f5841 »
2011-04-09 Fixed 503 responses when Redis is down.
171 return CMD_ACL_FAIL;
de5c2839 »
2010-12-27 Added IP range restriction.
172 }
173
4676cfeb »
2010-12-29 Refactoring.
174 if(cmd_is_subscribe(cmd)) {
bf2f5841 »
2011-04-09 Fixed 503 responses when Redis is down.
175 /* create a new connection to Redis */
b01cb75d »
2011-04-13 Disconnect broken SUBSCRIBE clients.
176 cmd->ac = (redisAsyncContext*)pool_connect(w->pool, 0);
177
178 /* register with the client, used upon disconnection */
179 client->pub_sub = cmd;
bf2f5841 »
2011-04-09 Fixed 503 responses when Redis is down.
180 } else {
181 /* get a connection from the pool */
b01cb75d »
2011-04-13 Disconnect broken SUBSCRIBE clients.
182 cmd->ac = (redisAsyncContext*)pool_get_context(w->pool);
2c980a21 »
2010-12-26 First try.
183 }
184
a3aa1a92 »
2011-01-03 Bugfix in RAW mode, more code doc.
185 /* no args (e.g. INFO command) */
2507fcee »
2010-12-21 Added JSON output.
186 if(!slash) {
b01cb75d »
2011-04-13 Disconnect broken SUBSCRIBE clients.
187 if(!cmd->ac) {
513982d8 »
2011-04-12 Added asynchronous reconnect, fixed memory leak.
188 cmd_free(cmd);
a91b7b13 »
2011-04-09 Unavailability bugfix.
189 return CMD_REDIS_UNAVAIL;
190 }
b01cb75d »
2011-04-13 Disconnect broken SUBSCRIBE clients.
191 redisAsyncCommandArgv(cmd->ac, f_format, cmd, 1,
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
192 (const char **)cmd->argv, cmd->argv_len);
bf2f5841 »
2011-04-09 Fixed 503 responses when Redis is down.
193 return CMD_SENT;
2507fcee »
2010-12-21 Added JSON output.
194 }
195 p = slash + 1;
196 while(p < uri + uri_len) {
197
198 const char *arg = p;
199 int arg_len;
d9d85ca1 »
2011-01-22 Fix realloc bug.
200 char *next = memchr(arg, '/', uri_len - (arg-uri));
5ca45a54 »
2011-01-03 Working custom handler.
201 if(!next || next > uri + uri_len) { /* last argument */
202 p = uri + uri_len;
203 arg_len = p - arg;
204 } else { /* found a slash */
2507fcee »
2010-12-21 Added JSON output.
205 arg_len = next - arg;
206 p = next + 1;
207 }
208
209 /* record argument */
4448b0fa »
2011-01-03 Proper decoding of URL parameters.
210 cmd->argv[cur_param] = decode_uri(arg, arg_len, &cmd->argv_len[cur_param], 1);
2507fcee »
2010-12-21 Added JSON output.
211 cur_param++;
212 }
213
a3ee623c »
2011-01-09 File uploads using HTTP PUT.
214 if(body && body_len) { /* PUT request */
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
215 cmd->argv[cur_param] = malloc(body_len);
216 memcpy(cmd->argv[cur_param], body, body_len);
a3ee623c »
2011-01-09 File uploads using HTTP PUT.
217 cmd->argv_len[cur_param] = body_len;
218 }
219
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
220 /* send it off! */
b01cb75d »
2011-04-13 Disconnect broken SUBSCRIBE clients.
221 if(cmd->ac) {
222 cmd_send(cmd, f_format);
bf2f5841 »
2011-04-09 Fixed 503 responses when Redis is down.
223 return CMD_SENT;
4448b0fa »
2011-01-03 Proper decoding of URL parameters.
224 }
bf2f5841 »
2011-04-09 Fixed 503 responses when Redis is down.
225 /* failed to find a suitable connection to Redis. */
513982d8 »
2011-04-12 Added asynchronous reconnect, fixed memory leak.
226 cmd_free(cmd);
bf2f5841 »
2011-04-09 Fixed 503 responses when Redis is down.
227 return CMD_REDIS_UNAVAIL;
2507fcee »
2010-12-21 Added JSON output.
228 }
229
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
230 void
b01cb75d »
2011-04-13 Disconnect broken SUBSCRIBE clients.
231 cmd_send(struct cmd *cmd, formatting_fun f_format) {
232 redisAsyncCommandArgv(cmd->ac, f_format, cmd, cmd->count,
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
233 (const char **)cmd->argv, cmd->argv_len);
234 }
6e3c4240 »
2011-01-04 Cleanup.
235
a3aa1a92 »
2011-01-03 Bugfix in RAW mode, more code doc.
236 /**
6e3c4240 »
2011-01-04 Cleanup.
237 * Select Content-Type and processing function.
a3aa1a92 »
2011-01-03 Bugfix in RAW mode, more code doc.
238 */
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
239 int
bbec5c65 »
2011-01-22 Bugfix, restored forced content-type.
240 cmd_select_format(struct http_client *client, struct cmd *cmd,
241 const char *uri, size_t uri_len, formatting_fun *f_format) {
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
242
71bc9e39 »
2011-01-05 Added a few content types, added support for ?type.
243 const char *ext;
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
244 int ext_len = -1;
245 unsigned int i;
e2f2b365 »
2010-12-26 Added RAW output.
246
6e3c4240 »
2011-01-04 Cleanup.
247 /* those are the available reply formats */
248 struct reply_format {
249 const char *s;
250 size_t sz;
251 formatting_fun f;
252 const char *ct;
253 };
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
254 struct reply_format funs[] = {
255 {.s = "json", .sz = 4, .f = json_reply, .ct = "application/json"},
256 {.s = "raw", .sz = 3, .f = raw_reply, .ct = "binary/octet-stream"},
e4d27387 »
2011-02-01 BSON support.
257 {.s = "bson", .sz = 4, .f = bson_reply, .ct = "application/bson"},
4abc4fc4 »
2011-01-09 Support for .bin as binary/octet-stream
258
259 {.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.
260 {.s = "txt", .sz = 3, .f = custom_type_reply, .ct = "text/plain"},
261 {.s = "html", .sz = 4, .f = custom_type_reply, .ct = "text/html"},
71bc9e39 »
2011-01-05 Added a few content types, added support for ?type.
262 {.s = "xhtml", .sz = 5, .f = custom_type_reply, .ct = "application/xhtml+xml"},
263 {.s = "xml", .sz = 3, .f = custom_type_reply, .ct = "text/xml"},
264
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
265 {.s = "png", .sz = 3, .f = custom_type_reply, .ct = "image/png"},
71bc9e39 »
2011-01-05 Added a few content types, added support for ?type.
266 {.s = "jpg", .sz = 3, .f = custom_type_reply, .ct = "image/jpeg"},
267 {.s = "jpeg", .sz = 4, .f = custom_type_reply, .ct = "image/jpeg"},
1b6f36bd »
2011-03-02 Added Content-Type for JS and CSS files.
268
269 {.s = "js", .sz = 2, .f = custom_type_reply, .ct = "application/javascript"},
270 {.s = "css", .sz = 3, .f = custom_type_reply, .ct = "text/css"},
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
271 };
e2f2b365 »
2010-12-26 Added RAW output.
272
6e3c4240 »
2011-01-04 Cleanup.
273 /* default */
1ea7cd07 »
2011-01-03 Special GET formatter for key + content-type key.
274 *f_format = json_reply;
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
275
276 /* find extension */
277 for(ext = uri + uri_len - 1; ext != uri && *ext != '/'; --ext) {
278 if(*ext == '.') {
279 ext++;
280 ext_len = uri + uri_len - ext;
e2f2b365 »
2010-12-26 Added RAW output.
281 break;
282 }
283 }
6e3c4240 »
2011-01-04 Cleanup.
284 if(!ext_len) return uri_len; /* nothing found */
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
285
286 /* find function for the given extension */
287 for(i = 0; i < sizeof(funs)/sizeof(funs[0]); ++i) {
288 if(ext_len == (int)funs[i].sz && strncmp(ext, funs[i].s, ext_len) == 0) {
102f9fcd »
2011-01-05 Started adding Accept support.
289
290 if(cmd->mime_free) free(cmd->mime);
291 cmd->mime = (char*)funs[i].ct;
292 cmd->mime_free = 0;
293
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
294 *f_format = funs[i].f;
295 }
296 }
71bc9e39 »
2011-01-05 Added a few content types, added support for ?type.
297
6026811c »
2011-01-23 Fix pub/sub. Valgrind is happy.
298 /* the user can force it with ?type=some/thing */
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
299 if(client->type) {
bbec5c65 »
2011-01-22 Bugfix, restored forced content-type.
300 *f_format = custom_type_reply;
5b7aa50e »
2011-04-08 Partial rewrite, adding WebSockets, threads, pool.
301 cmd->mime = strdup(client->type);
bbec5c65 »
2011-01-22 Bugfix, restored forced content-type.
302 cmd->mime_free = 1;
71bc9e39 »
2011-01-05 Added a few content types, added support for ?type.
303 }
bbec5c65 »
2011-01-22 Bugfix, restored forced content-type.
304
469e5160 »
2011-01-04 Removed content-type in another key, added suffixes instead.
305 return uri_len - ext_len - 1;
e2f2b365 »
2010-12-26 Added RAW output.
306 }
4676cfeb »
2010-12-29 Refactoring.
307
308 int
309 cmd_is_subscribe(struct cmd *cmd) {
310
9378544d »
2011-01-26 Fix subscribe leak.
311 if(cmd->count >= 1 &&
981fd54a »
2011-01-22 Fix Keep-Alive.
312 (strncasecmp(cmd->argv[0], "SUBSCRIBE", cmd->argv_len[0]) == 0 ||
313 strncasecmp(cmd->argv[0], "PSUBSCRIBE", cmd->argv_len[0]) == 0)) {
4676cfeb »
2010-12-29 Refactoring.
314 return 1;
315 }
316 return 0;
317 }
Something went wrong with that request. Please try again.