diff --git a/README.markdown b/README.markdown index 46dfbdd..e18ca5d 100644 --- a/README.markdown +++ b/README.markdown @@ -19,7 +19,6 @@ curl -d "GET/hello" http://127.0.0.1:7379/ * Add meta-data info per key (MIME type in a second key, for instance). * Find a way to format multi-bulk data without JSON. * Support PUT, DELETE, HEAD? -* Add JSONP callbacks. * Add logging. * Add support for Redis UNIX socket. * Enrich config file: @@ -58,4 +57,9 @@ $ curl http://127.0.0.1:7379/TYPE/y // error, which is basically a status $ curl http://127.0.0.1:7379/MAKE-ME-COFFEE {"MAKE-ME-COFFEE":[false,"ERR unknown command 'MAKE-ME-COFFEE'"]} + + +// JSONP callback: +$ curl "http://127.0.0.1:7379/TYPE/y?jsonp=myCustomFunction" +myCustomFunction({"TYPE":[true,"string"]}) diff --git a/cmd.c b/cmd.c index 14b05c8..6ff774c 100644 --- a/cmd.c +++ b/cmd.c @@ -30,8 +30,10 @@ cmd_free(struct cmd *c) { } void -cmd_run(redisAsyncContext *c, struct evhttp_request *rq, const char *uri, size_t uri_len) { +cmd_run(redisAsyncContext *c, struct evhttp_request *rq, + const char *uri, size_t uri_len) { + char *qmark = strchr(uri, '?'); char *slash = strchr(uri, '/'); int cmd_len; int param_count = 0, cur_param = 1; @@ -41,6 +43,9 @@ cmd_run(redisAsyncContext *c, struct evhttp_request *rq, const char *uri, size_t const char *p; /* count arguments */ + if(qmark) { + uri_len = qmark - uri; + } for(p = uri; p && p < uri + uri_len; param_count++) { p = strchr(p+1, '/'); } @@ -53,6 +58,9 @@ cmd_run(redisAsyncContext *c, struct evhttp_request *rq, const char *uri, size_t cmd_len = uri_len; } + /* parse URI parameters */ + evhttp_parse_query(uri, &cmd->uri_params); + /* there is always a first parameter, it's the command name */ cmd->argv[0] = uri; cmd->argv_len[0] = cmd_len; diff --git a/cmd.h b/cmd.h index 55fc119..3dd470d 100644 --- a/cmd.h +++ b/cmd.h @@ -3,6 +3,9 @@ #include #include +#include +#include +#include struct evhttp_request; @@ -12,6 +15,8 @@ struct cmd { const char **argv; size_t *argv_len; struct evhttp_request *rq; + + struct evkeyvalq uri_params; }; struct cmd * @@ -21,6 +26,7 @@ void cmd_free(struct cmd *c); void -cmd_run(redisAsyncContext *c, struct evhttp_request *rq, const char *uri, size_t uri_len); +cmd_run(redisAsyncContext *c, struct evhttp_request *rq, + const char *uri, size_t uri_len); #endif diff --git a/json.c b/json.c index 00ca191..90ff00b 100644 --- a/json.c +++ b/json.c @@ -28,8 +28,9 @@ json_reply(redisAsyncContext *c, void *r, void *privdata) { /* encode redis reply as JSON */ j = json_wrap_redis_reply(cmd, r); - /* get JSON as string */ - json_reply = json_dumps(j, JSON_COMPACT); + /* get JSON as string, possibly with JSONP wrapper */ + json_reply = json_string_output(j, cmd); + /* send reply */ body = evbuffer_new(); @@ -103,3 +104,32 @@ json_wrap_redis_reply(const struct cmd *cmd, const redisReply *r) { return jroot; } + +char * +json_string_output(json_t *j, struct cmd *cmd) { + struct evkeyval *kv; + + char *json_reply = json_dumps(j, JSON_COMPACT); + + /* check for JSONP */ + TAILQ_FOREACH(kv, &cmd->uri_params, next) { + if(strcmp(kv->key, "jsonp") == 0) { + size_t json_len = strlen(json_reply); + size_t val_len = strlen(kv->value); + size_t ret_len = val_len + 1 + json_len + 1; + char *ret = calloc(1 + ret_len, 1); + + memcpy(ret, kv->value, val_len); + ret[val_len]='('; + memcpy(ret + val_len + 1, json_reply, json_len); + ret[val_len + 1 + json_len] = ')'; + free(json_reply); + + return ret; + } + } + + + return json_reply; +} + diff --git a/json.h b/json.h index c49fb0c..a81d6cb 100644 --- a/json.h +++ b/json.h @@ -10,5 +10,7 @@ struct cmd; void json_reply(redisAsyncContext *c, void *r, void *privdata); +char * +json_string_output(json_t *j, struct cmd *cmd); #endif