diff --git a/README.markdown b/README.markdown index 38b6def..f89a214 100644 --- a/README.markdown +++ b/README.markdown @@ -182,6 +182,7 @@ Several content-types are available: * `.png` for `image/png` * `jpg` or `jpeg` for `image/jpeg` * Any other with the `?type=anything/youwant` query string. +* Add a custom separator for list responses with `?sep=,` query string.
curl -v "http://127.0.0.1:7379/GET/hello.html" diff --git a/client.c b/client.c index e19708b..a17cf39 100644 --- a/client.c +++ b/client.c @@ -124,6 +124,9 @@ http_client_on_query_string(struct http_parser *parser, const char *at, size_t s || (key_len == 8 && strncmp(key, "callback", 8) == 0)) { c->jsonp = calloc(1 + val_len, 1); memcpy(c->jsonp, val, val_len); + } else if(key_len == 3 && strncmp(key, "sep", 3) == 0) { + c->separator = calloc(1 + val_len, 1); + memcpy(c->separator, val, val_len); } else if(key_len == 8 && strncmp(key, "filename", 8) == 0) { c->filename = wrap_filename(val, val_len); } diff --git a/client.h b/client.h index ae05fce..71369e5 100644 --- a/client.h +++ b/client.h @@ -51,6 +51,7 @@ struct http_client { char *type; /* forced output content-type */ char *jsonp; /* jsonp wrapper */ + char *separator; /* list separator for raw lists */ char *filename; /* content-disposition */ struct cmd *pub_sub; diff --git a/cmd.c b/cmd.c index d193bf8..f761bc4 100644 --- a/cmd.c +++ b/cmd.c @@ -48,6 +48,7 @@ cmd_free(struct cmd *c) { free(c->argv_len); free(c->jsonp); + free(c->separator); free(c->if_none_match); if(c->mime_free) free(c->mime); @@ -113,6 +114,11 @@ cmd_setup(struct cmd *cmd, struct http_client *client) { client->jsonp = NULL; } + if(client->separator) { /* transfer pointer ownership */ + cmd->separator = client->separator; + client->separator = NULL; + } + if(client->filename) { /* transfer pointer ownership */ cmd->filename = client->filename; client->filename = NULL; diff --git a/cmd.h b/cmd.h index c527bf6..bcd21f3 100644 --- a/cmd.h +++ b/cmd.h @@ -34,6 +34,7 @@ struct cmd { char *if_none_match; /* used with ETags */ char *jsonp; /* jsonp wrapper */ + char *separator; /* list separator for raw lists */ int keep_alive; /* various flags */ diff --git a/formats/custom-type.c b/formats/custom-type.c index 67b7b9c..3fc6e08 100644 --- a/formats/custom-type.c +++ b/formats/custom-type.c @@ -8,7 +8,7 @@ #includestatic char * -custom_array(const redisReply *r, size_t *sz); +custom_array(struct cmd *cmd, const redisReply *r, size_t *sz); void custom_type_reply(redisAsyncContext *c, void *r, void *privdata) { @@ -54,7 +54,7 @@ custom_type_reply(redisAsyncContext *c, void *r, void *privdata) { format_send_reply(cmd, int_buffer, int_len, cmd->mime); return; case REDIS_REPLY_ARRAY: - array_out = custom_array(r, &sz); + array_out = custom_array(cmd, r, &sz); format_send_reply(cmd, array_out, sz, cmd->mime); free(array_out); return; @@ -73,10 +73,14 @@ custom_type_reply(redisAsyncContext *c, void *r, void *privdata) { } static char * -custom_array(const redisReply *r, size_t *sz) { +custom_array(struct cmd *cmd, const redisReply *r, size_t *sz) { unsigned int i; char *ret, *p; + size_t sep_len = 0; + + if(cmd->separator) + sep_len = strlen(cmd->separator); /* compute size */ *sz = 0; @@ -84,6 +88,8 @@ custom_array(const redisReply *r, size_t *sz) { redisReply *e = r->element[i]; switch(e->type) { case REDIS_REPLY_STRING: + if(sep_len && i != 0) + *sz += sep_len; *sz += e->len; break; @@ -98,6 +104,10 @@ custom_array(const redisReply *r, size_t *sz) { redisReply *e = r->element[i]; switch(e->type) { case REDIS_REPLY_STRING: + if(sep_len && i != 0) { + memcpy(p, cmd->separator, sep_len); + p += sep_len; + } memcpy(p, e->str, e->len); p += e->len; break; diff --git a/tests/basic.py b/tests/basic.py index 1d55d2d..99c3565 100755 --- a/tests/basic.py +++ b/tests/basic.py @@ -92,6 +92,23 @@ class TestJSON(TestWebdis): self.assertTrue(obj['UNKNOWN'][0] == False) self.assertTrue(isinstance(obj['UNKNOWN'][1], unicode)) +class TestCustom(TestWebdis): + def test_list(self): + "List responses with custom format" + self.query('DEL/hello') + self.query('RPUSH/hello/a/b/c') + f = self.query('LRANGE/hello/0/-1.txt') + self.assertTrue(f.headers.getheader('Content-Type') == 'text/plain') + self.assertTrue(f.read() == "abc") + + def test_separator(self): + "Separator in list responses with custom format" + self.query('DEL/hello') + self.query('RPUSH/hello/a/b/c') + f = self.query('LRANGE/hello/0/-1.txt?sep=--') + self.assertTrue(f.headers.getheader('Content-Type') == 'text/plain') + self.assertTrue(f.read() == "a--b--c") + class TestRaw(TestWebdis): def test_set(self):