diff --git a/README.markdown b/README.markdown index 6733630..b34136f 100644 --- a/README.markdown +++ b/README.markdown @@ -33,6 +33,8 @@ curl -d "GET/hello" http://127.0.0.1:7379/ * Logs, with a configurable verbosity. * Cross-origin requests, usable with XMLHttpRequest2 (Cross-Origin Resource Sharing - CORS). * File upload with PUT. +* With the JSON output, the return value of INFO is parsed and transformed into an object. +* Optional daemonize. # Ideas, TODO... * Fix crash on ACL rejection. diff --git a/conf.c b/conf.c index 37696c3..6402acb 100644 --- a/conf.c +++ b/conf.c @@ -34,6 +34,7 @@ conf_read(const char *filename) { conf->group = getgid(); conf->logfile = "webdis.log"; conf->verbosity = WEBDIS_NOTICE; + conf->daemonize = 0; j = json_load_file(filename, 0, &error); if(!j) { @@ -75,6 +76,8 @@ conf_read(const char *filename) { if(tmp < 0) conf->verbosity = WEBDIS_ERROR; else if(tmp > (int)WEBDIS_DEBUG) conf->verbosity = WEBDIS_DEBUG; else conf->verbosity = (log_level)tmp; + } else if(strcmp(json_object_iter_key(kv), "daemonize") == 0 && json_typeof(jtmp) == JSON_TRUE) { + conf->daemonize = 1; } } diff --git a/conf.h b/conf.h index 2a3e566..4ddf8a4 100644 --- a/conf.h +++ b/conf.h @@ -15,6 +15,9 @@ struct conf { char *http_host; short http_port; + /* daemonize process, off by default */ + int daemonize; + /* ACL */ struct acl *perms; diff --git a/formats/json.c b/formats/json.c index 160a834..d55dc75 100644 --- a/formats/json.c +++ b/formats/json.c @@ -45,6 +45,50 @@ json_reply(redisAsyncContext *c, void *r, void *privdata) { free(jstr); } +/** + * Parse info message and return object. + */ +static json_t * +json_info_reply(const char *s) { + const char *p = s; + size_t sz = strlen(s); + + json_t *jroot = json_object(); + + /* TODO: handle new format */ + + while(p < s + sz) { + char *key, *val, *nl, *colon; + + /* find key */ + colon = strchr(p, ':'); + if(!colon) { + break; + } + key = calloc(colon - p + 1, 1); + memcpy(key, p, colon - p); + p = colon + 1; + + /* find value */ + nl = strchr(p, '\r'); + if(!nl) { + free(key); + break; + } + val = calloc(nl - p + 1, 1); + memcpy(val, p, nl - p); + p = nl + 1; + if(*p == '\n') p++; + + /* add to object */ + json_object_set_new(jroot, key, json_string(val)); + free(key); + free(val); + } + + return jroot; +} + static json_t * json_wrap_redis_reply(const struct cmd *cmd, const redisReply *r) { @@ -61,6 +105,7 @@ json_wrap_redis_reply(const struct cmd *cmd, const redisReply *r) { verb = strdup(""); } + switch(r->type) { case REDIS_REPLY_STATUS: case REDIS_REPLY_ERROR: @@ -72,7 +117,11 @@ json_wrap_redis_reply(const struct cmd *cmd, const redisReply *r) { break; case REDIS_REPLY_STRING: - json_object_set_new(jroot, verb, json_string(r->str)); + if(strcasecmp(verb, "INFO") == 0) { + json_object_set_new(jroot, verb, json_info_reply(r->str)); + } else { + json_object_set_new(jroot, verb, json_string(r->str)); + } break; case REDIS_REPLY_INTEGER: diff --git a/server.c b/server.c index 096d033..3b624d7 100644 --- a/server.c +++ b/server.c @@ -187,10 +187,31 @@ on_possible_accept(int fd, short event, void *ctx) { http_client_serve(c); } +/* Taken from Redis. */ +void +server_daemonize(void) { + int fd; + + if (fork() != 0) exit(0); /* parent exits */ + setsid(); /* create a new session */ + + /* Every output goes to /dev/null. */ + if ((fd = open("/dev/null", O_RDWR, 0)) != -1) { + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + if (fd > STDERR_FILENO) close(fd); + } +} void server_start(struct server *s) { + + if(s->cfg->daemonize) { + server_daemonize(); + } + /* ignore sigpipe */ #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); diff --git a/webdis.json b/webdis.json index 15db98d..4766261 100644 --- a/webdis.json +++ b/webdis.json @@ -7,6 +7,8 @@ "http_host": "0.0.0.0", "http_port": 7379, + "daemonize": false, + "acl": [ { "disabled": ["DEBUG"]