Skip to content
This repository
Newer
Older
100644 217 lines (163 sloc) 4.347 kb
2507fcee »
2010-12-21 Added JSON output.
1 #include "cmd.h"
e2f2b365 »
2010-12-26 Added RAW output.
2 #include "server.h"
de5c2839 »
2010-12-27 Added IP range restriction.
3 #include "conf.h"
e2f2b365 »
2010-12-26 Added RAW output.
4
5 #include "formats/json.h"
6 #include "formats/raw.h"
2507fcee »
2010-12-21 Added JSON output.
7
8 #include <stdlib.h>
9 #include <string.h>
10 #include <hiredis/hiredis.h>
de5c2839 »
2010-12-27 Added IP range restriction.
11 #include <netinet/in.h>
12 #include <arpa/inet.h>
2507fcee »
2010-12-21 Added JSON output.
13
14 struct cmd *
15 cmd_new(struct evhttp_request *rq, int count) {
16
17 struct cmd *c = calloc(1, sizeof(struct cmd));
18
19 c->rq = rq;
20 c->count = count;
21
22 c->argv = calloc(count, sizeof(char*));
23 c->argv_len = calloc(count, sizeof(size_t));
24
25 return c;
26 }
27
28
29 void
30 cmd_free(struct cmd *c) {
31
32 free(c->argv);
33 free(c->argv_len);
34
35 free(c);
36 }
37
d8f6460e »
2010-12-29 Pub/sub progress...
38 struct pubsub_client {
39 struct server *s;
40 struct evhttp_request *rq;
41 };
42
794a76db »
2010-12-26 Added debug info, trying to find a way to support SUBSCRIBE.
43 void __redisAsyncDisconnect(redisAsyncContext *ac);
44 void on_http_disconnect(struct evhttp_connection *evcon, void *ctx) {
d8f6460e »
2010-12-29 Pub/sub progress...
45 struct pubsub_client *ps = ctx;
46
47 (void)evcon;
48
49 if(ps->s->ac->replies.head) { /* TODO: proper free. */
114d6c9a »
2010-12-29 Cleaned up PUB/SUB leaks.
50 if(ps->s->ac->replies.head->privdata) {
51 cmd_free(ps->s->ac->replies.head->privdata);
52 }
d8f6460e »
2010-12-29 Pub/sub progress...
53 ps->s->ac->replies.head->privdata = NULL;
54 }
240f05ea »
2010-12-29 PUB/SUB seems to work without crashing...
55 redisAsyncFree(ps->s->ac);
d8f6460e »
2010-12-29 Pub/sub progress...
56 free(ps);
794a76db »
2010-12-26 Added debug info, trying to find a way to support SUBSCRIBE.
57 }
58
de5c2839 »
2010-12-27 Added IP range restriction.
59 int
60 cmd_authorized(struct conf *cfg, struct evhttp_request *rq, const char *verb, size_t verb_len) {
61
2f5454ca »
2010-12-29 Merge branch 'master' into pubsub
62 char *always_off[] = {"MULTI", "EXEC", "WATCH", "DISCARD"};
f33ecf71 »
2010-12-27 Disabled MULTI/EXEC/WATCH/DISCARD.
63
de5c2839 »
2010-12-27 Added IP range restriction.
64 struct disabled_command *dc;
65 unsigned int i;
66
67 char *client_ip;
68 u_short client_port;
69 in_addr_t client_addr;
70
f33ecf71 »
2010-12-27 Disabled MULTI/EXEC/WATCH/DISCARD.
71 /* some commands are always disabled, regardless of the config file. */
72 for(i = 0; i < sizeof(always_off) / sizeof(always_off[0]); ++i) {
73 if(strncasecmp(always_off[i], verb, verb_len) == 0) {
74 return 0;
75 }
76 }
77
78
de5c2839 »
2010-12-27 Added IP range restriction.
79 /* find client's address */
80 evhttp_connection_get_peer(rq->evcon, &client_ip, &client_port);
81 client_addr = ntohl(inet_addr(client_ip));
82
83 for(dc = cfg->disabled; dc; dc = dc->next) {
84 /* CIDR test */
85
86 if((client_addr & dc->mask) != (dc->subnet & dc->mask)) {
87 continue;
88 }
89
90 /* matched an ip */
91 for(i = 0; i < dc->count; ++i) {
92 if(strncasecmp(dc->commands[i], verb, verb_len) == 0) {
93 return 0;
94 }
95 }
96 }
97
98 return 1;
99 }
100
101 int
e2f2b365 »
2010-12-26 Added RAW output.
102 cmd_run(struct server *s, struct evhttp_request *rq,
9d2beace »
2010-12-22 Added JSONP.
103 const char *uri, size_t uri_len) {
2507fcee »
2010-12-21 Added JSON output.
104
9d2beace »
2010-12-22 Added JSONP.
105 char *qmark = strchr(uri, '?');
2507fcee »
2010-12-21 Added JSON output.
106 char *slash = strchr(uri, '/');
e2f2b365 »
2010-12-26 Added RAW output.
107 const char *p;
2507fcee »
2010-12-21 Added JSON output.
108 int cmd_len;
109 int param_count = 0, cur_param = 1;
110
111 struct cmd *cmd;
e2f2b365 »
2010-12-26 Added RAW output.
112 formatting_fun fun;
2507fcee »
2010-12-21 Added JSON output.
113
114 /* count arguments */
9d2beace »
2010-12-22 Added JSONP.
115 if(qmark) {
116 uri_len = qmark - uri;
117 }
2507fcee »
2010-12-21 Added JSON output.
118 for(p = uri; p && p < uri + uri_len; param_count++) {
119 p = strchr(p+1, '/');
120 }
121
122 cmd = cmd_new(rq, param_count);
123
124 if(slash) {
125 cmd_len = slash - uri;
126 } else {
127 cmd_len = uri_len;
128 }
129
9d2beace »
2010-12-22 Added JSONP.
130 /* parse URI parameters */
131 evhttp_parse_query(uri, &cmd->uri_params);
132
e2f2b365 »
2010-12-26 Added RAW output.
133 /* get output formatting function */
134 fun = get_formatting_funtion(&cmd->uri_params);
135
2507fcee »
2010-12-21 Added JSON output.
136 /* there is always a first parameter, it's the command name */
137 cmd->argv[0] = uri;
138 cmd->argv_len[0] = cmd_len;
139
2f5454ca »
2010-12-29 Merge branch 'master' into pubsub
140
de5c2839 »
2010-12-27 Added IP range restriction.
141 /* check that the client is able to run this command */
142 if(!cmd_authorized(s->cfg, rq, cmd->argv[0], cmd->argv_len[0])) {
143 return -1;
144 }
145
2c980a21 »
2010-12-26 First try.
146 /* check if we have to split the connection */
4676cfeb »
2010-12-29 Refactoring.
147 if(cmd_is_subscribe(cmd)) {
d8f6460e »
2010-12-29 Pub/sub progress...
148 struct pubsub_client *ps;
149 ps = calloc(1, sizeof(struct pubsub_client));
150 ps->s = s = server_copy(s);
151
152 ps->rq = rq;
153
154 evhttp_connection_set_closecb(rq->evcon, on_http_disconnect, ps);
2c980a21 »
2010-12-26 First try.
155 }
156
2507fcee »
2010-12-21 Added JSON output.
157 if(!slash) {
e2f2b365 »
2010-12-26 Added RAW output.
158 redisAsyncCommandArgv(s->ac, fun, cmd, 1, cmd->argv, cmd->argv_len);
de5c2839 »
2010-12-27 Added IP range restriction.
159 return 0;
2507fcee »
2010-12-21 Added JSON output.
160 }
161 p = slash + 1;
162 while(p < uri + uri_len) {
163
164 const char *arg = p;
165 int arg_len;
166 char *next = strchr(arg, '/');
167 if(next) { /* found a slash */
168 arg_len = next - arg;
169 p = next + 1;
170 } else { /* last argument */
171 arg_len = uri + uri_len - arg;
172 p = uri + uri_len;
173 }
174
175 /* record argument */
176 cmd->argv[cur_param] = arg;
177 cmd->argv_len[cur_param] = arg_len;
178
179 cur_param++;
180 }
181
e2f2b365 »
2010-12-26 Added RAW output.
182 redisAsyncCommandArgv(s->ac, fun, cmd, param_count, cmd->argv, cmd->argv_len);
de5c2839 »
2010-12-27 Added IP range restriction.
183 return 0;
2507fcee »
2010-12-21 Added JSON output.
184 }
185
e2f2b365 »
2010-12-26 Added RAW output.
186
187
188 formatting_fun
189 get_formatting_funtion(struct evkeyvalq *params) {
190
191 struct evkeyval *kv;
192
193 /* check for JSONP */
194 TAILQ_FOREACH(kv, params, next) {
195 if(strcmp(kv->key, "format") == 0) {
196 if(strcmp(kv->value, "raw") == 0) {
197 return raw_reply;
198 } else if(strcmp(kv->value, "json") == 0) {
199 return json_reply;
200 }
201 break;
202 }
203 }
204
205 return json_reply;
206 }
4676cfeb »
2010-12-29 Refactoring.
207
208 int
209 cmd_is_subscribe(struct cmd *cmd) {
210
211 if(strncasecmp(cmd->argv[0], "SUBSCRIBE", cmd->argv_len[0]) == 0 ||
212 strncasecmp(cmd->argv[0], "PSUBSCRIBE", cmd->argv_len[0]) == 0) {
213 return 1;
214 }
215 return 0;
216 }
Something went wrong with that request. Please try again.