diff --git a/Makefile b/Makefile index 38af0d9..abd639b 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ HTTP_PARSER_OBJS=http-parser/http_parser.o DEPS=$(FORMAT_OBJS) $(HIREDIS_OBJ) $(JANSSON_OBJ) $(HTTP_PARSER_OBJS) OBJS=webdis.o conf.o cmd.o slog.o server.o libb64/cencode.o acl.o md5/md5.o http.o $(DEPS) -CFLAGS=-O3 -Wall -Wextra -I. -Ijansson/src -Ihttp-parser +CFLAGS=-O0 -ggdb -Wall -Wextra -I. -Ijansson/src -Ihttp-parser LDFLAGS=-levent all: $(OUT) Makefile diff --git a/cmd.c b/cmd.c index 5961191..7b52590 100644 --- a/cmd.c +++ b/cmd.c @@ -13,11 +13,11 @@ #include struct cmd * -cmd_new(struct evhttp_request *rq, int count) { +cmd_new(struct http_client *client, int count) { struct cmd *c = calloc(1, sizeof(struct cmd)); - c->rq = rq; + c->client = client; c->count = count; c->argv = calloc(count, sizeof(char*)); @@ -86,10 +86,11 @@ decode_uri(const char *uri, size_t length, size_t *out_len, int always_decode_pl int -cmd_run(struct server *s, struct evhttp_request *rq, - const char *uri, size_t uri_len, const char *body, size_t body_len) { +cmd_run(struct server *s, struct http_client *client, + const char *uri, size_t uri_len, + const char *body, size_t body_len) { - char *qmark = strchr(uri, '?'); + char *qmark = memchr(uri, '?', uri_len); char *slash; const char *p; int cmd_len; @@ -104,17 +105,17 @@ cmd_run(struct server *s, struct evhttp_request *rq, uri_len = qmark - uri; } for(p = uri; p && p < uri + uri_len; param_count++) { - p = strchr(p+1, '/'); + p = memchr(p+1, '/', uri_len - (p+1-uri)); } if(body && body_len) { /* PUT request */ param_count++; } - cmd = cmd_new(rq, param_count); + cmd = cmd_new(client, param_count); - /* parse URI parameters */ - evhttp_parse_query(uri, &cmd->uri_params); + /* FIXME: parse URI parameters */ + /* evhttp_parse_query(uri, &cmd->uri_params); */ /* get output formatting function */ uri_len = cmd_select_format(cmd, uri, uri_len, &f_format); @@ -132,12 +133,15 @@ cmd_run(struct server *s, struct evhttp_request *rq, cmd->argv_len[0] = cmd_len; - /* check that the client is able to run this command */ + /* FIXME: check that the client is able to run this command */ + /* if(!acl_allow_command(cmd, s->cfg, rq)) { return -1; } + */ - /* check if we have to split the connection */ + /* FIXME:check if we have to split the connection */ + /* if(cmd_is_subscribe(cmd)) { struct pubsub_client *ps; @@ -147,6 +151,7 @@ cmd_run(struct server *s, struct evhttp_request *rq, ps->rq = rq; evhttp_connection_set_closecb(rq->evcon, on_http_disconnect, ps); } + */ /* no args (e.g. INFO command) */ if(!slash) { @@ -158,7 +163,7 @@ cmd_run(struct server *s, struct evhttp_request *rq, const char *arg = p; int arg_len; - char *next = strchr(arg, '/'); + char *next = memchr(arg, '/', uri_len - (arg-p)); if(!next || next > uri + uri_len) { /* last argument */ p = uri + uri_len; arg_len = p - arg; @@ -246,7 +251,8 @@ cmd_select_format(struct cmd *cmd, const char *uri, size_t uri_len, formatting_f } } - /* the user can force it with ?type=some/thing */ + /* FIXME:the user can force it with ?type=some/thing */ + /* TAILQ_FOREACH(kv, &cmd->uri_params, next) { if(strcmp(kv->key, "type") == 0) { @@ -257,6 +263,7 @@ cmd_select_format(struct cmd *cmd, const char *uri, size_t uri_len, formatting_f break; } } + */ return uri_len - ext_len - 1; } diff --git a/cmd.h b/cmd.h index f7b869a..3ae726c 100644 --- a/cmd.h +++ b/cmd.h @@ -8,6 +8,7 @@ #include struct evhttp_request; +struct http_client; struct server; struct cmd; @@ -18,9 +19,7 @@ struct cmd { int count; const char **argv; size_t *argv_len; - struct evhttp_request *rq; - - struct evkeyvalq uri_params; + struct http_client *client; int started_responding; @@ -38,13 +37,13 @@ struct pubsub_client { }; struct cmd * -cmd_new(struct evhttp_request *rq, int count); +cmd_new(struct http_client *client, int count); void cmd_free(struct cmd *c); int -cmd_run(struct server *s, struct evhttp_request *rq, +cmd_run(struct server *s, struct http_client *client, const char *uri, size_t uri_len, const char *body, size_t body_len); diff --git a/formats/common.c b/formats/common.c index 46c60ae..577fd0a 100644 --- a/formats/common.c +++ b/formats/common.c @@ -1,8 +1,8 @@ #include "common.h" #include "cmd.h" +#include "http.h" #include "md5/md5.h" -#include #include /* TODO: replace this with a faster hash function */ @@ -31,13 +31,8 @@ char *etag_new(const char *p, size_t sz) { void format_send_reply(struct cmd *cmd, const char *p, size_t sz, const char *content_type) { - struct evbuffer *body; int free_cmd = 1; - /* send reply */ - body = evbuffer_new(); - evbuffer_add(body, p, sz); - if(cmd_is_subscribe(cmd)) { free_cmd = 0; @@ -45,35 +40,36 @@ format_send_reply(struct cmd *cmd, const char *p, size_t sz, const char *content /* start streaming */ if(cmd->started_responding == 0) { cmd->started_responding = 1; - evhttp_add_header(cmd->rq->output_headers, "Content-Type", - cmd->mime?cmd->mime:content_type); + http_set_header(&cmd->client->out_content_type, cmd->mime?cmd->mime:content_type); + /*FIXME: evhttp_send_reply_start(cmd->rq, 200, "OK"); + */ } - evhttp_send_reply_chunk(cmd->rq, body); + /*FIXME: evhttp_send_reply_chunk(cmd->rq, body); */ } else { /* compute ETag */ char *etag = etag_new(p, sz); const char *if_none_match; - + /* FIXME */ +#if 1 /* check If-None-Match */ - if((if_none_match = evhttp_find_header(cmd->rq->input_headers, "If-None-Match")) - && strcmp(if_none_match, etag) == 0) { + if(0 /*FIXME:(if_none_match = evhttp_find_header(cmd->rq->input_headers, "If-None-Match")) + && strcmp(if_none_match, etag) == 0*/) { /* SAME! send 304. */ - evhttp_send_reply(cmd->rq, 304, "Not Modified", NULL); + /* evhttp_send_reply(cmd->rq, 304, "Not Modified", NULL); */ } else { - evhttp_add_header(cmd->rq->output_headers, "Content-Type", - cmd->mime?cmd->mime:content_type); - evhttp_add_header(cmd->rq->output_headers, "ETag", etag); - evhttp_send_reply(cmd->rq, 200, "OK", body); + http_set_header(&cmd->client->out_content_type, cmd->mime?cmd->mime:content_type); + http_set_header(&cmd->client->out_etag, etag); + http_send_reply(cmd->client, 200, "OK", p, sz); } +#endif free(etag); } /* cleanup */ - evbuffer_free(body); if(free_cmd) { - evhttp_clear_headers(&cmd->uri_params); + /*FIXME: evhttp_clear_headers(&cmd->uri_params); */ cmd_free(cmd); } } diff --git a/formats/custom-type.c b/formats/custom-type.c index e29505f..63461f0 100644 --- a/formats/custom-type.c +++ b/formats/custom-type.c @@ -16,7 +16,7 @@ custom_type_reply(redisAsyncContext *c, void *r, void *privdata) { int int_len; if(reply == NULL) { - evhttp_send_reply(cmd->rq, 404, "Not Found", NULL); + /* FIXME: evhttp_send_reply(cmd->rq, 404, "Not Found", NULL); */ return; } @@ -39,7 +39,7 @@ custom_type_reply(redisAsyncContext *c, void *r, void *privdata) { } /* couldn't make sense of what the client wanted. */ - evhttp_send_reply(cmd->rq, 400, "Bad request", NULL); + /* FIXME: evhttp_send_reply(cmd->rq, 400, "Bad request", NULL); */ cmd_free(cmd); } diff --git a/formats/json.c b/formats/json.c index 5a63f73..0e14bc6 100644 --- a/formats/json.c +++ b/formats/json.c @@ -24,7 +24,7 @@ json_reply(redisAsyncContext *c, void *r, void *privdata) { } if (reply == NULL) { - evhttp_send_reply(cmd->rq, 404, "Not Found", NULL); + http_send_reply(cmd->client, 404, "Not Found", NULL, 0); return; } @@ -107,7 +107,8 @@ json_string_output(json_t *j, struct cmd *cmd) { char *json_reply = json_dumps(j, JSON_COMPACT); - /* check for JSONP */ + /* FIXME: check for JSONP */ +#if 0 TAILQ_FOREACH(kv, &cmd->uri_params, next) { if(strcmp(kv->key, "jsonp") == 0) { size_t json_len = strlen(json_reply); @@ -124,7 +125,7 @@ json_string_output(json_t *j, struct cmd *cmd) { return ret; } } - +#endif return json_reply; } diff --git a/formats/raw.c b/formats/raw.c index 1a90318..cd6ff6a 100644 --- a/formats/raw.c +++ b/formats/raw.c @@ -19,7 +19,9 @@ raw_reply(redisAsyncContext *c, void *r, void *privdata) { (void)c; if (reply == NULL) { + /* FIXME evhttp_send_reply(cmd->rq, 404, "Not Found", NULL); + */ return; } diff --git a/http.c b/http.c index 38338e0..3bce157 100644 --- a/http.c +++ b/http.c @@ -1,5 +1,7 @@ #include "http.h" #include "server.h" +#include "slog.h" +#include "cmd.h" #include #include @@ -14,6 +16,8 @@ http_client_new(int fd, struct server *s) { c->settings.on_path = http_on_path; c->settings.on_body = http_on_body; + c->settings.on_message_complete = http_on_complete; + http_parser_init(&c->parser, HTTP_REQUEST); c->parser.data = c; @@ -65,6 +69,7 @@ http_client_free(struct http_client *c) { close(c->fd); free(c->buffer); + free((char*)c->out_content_type.s); free(c); } @@ -103,3 +108,81 @@ http_on_body(http_parser *p, const char *at, size_t length) { return 0; } + +int +http_on_complete(http_parser *p) { + struct http_client *c = p->data; + int ret; + + /* check that the command can be executed */ + switch(c->verb) { + case HTTP_GET: + /* slog(s, WEBDIS_DEBUG, uri); */ + ret = cmd_run(c->s, c, 1+c->path.s, c->path.sz-1, NULL, 0); + break; + + case HTTP_POST: + /*slog(s, WEBDIS_DEBUG, uri);*/ + ret = cmd_run(c->s, c, 1+c->body.s, c->body.sz-1, NULL, 0); + break; + + case HTTP_PUT: + /* slog(s, WEBDIS_DEBUG, uri); */ + ret = cmd_run(c->s, c, 1+c->path.s, c->path.sz-1, + c->body.s, c->body.sz); + break; + + case HTTP_OPTIONS: + /* on_options(rq); */ + return 0; + + default: + slog(c->s, WEBDIS_DEBUG, "405"); + /* evhttp_send_reply(rq, 405, "Method Not Allowed", NULL); */ + return 0; + } + return 0; +} + +void +http_send_reply(struct http_client *c, short code, const char *msg, + const char *body, size_t body_len) { + + char *out = NULL; + size_t sz = 0; + int ret = 0, ok; + + const char *ct = c->out_content_type.s; + if(!ct) { + ct = "text/html"; + } + + while(1) { + ret = snprintf(out, sz, "HTTP/1.1 %d %s\r\n" + "Content-Type: %s\r\n" + "Content-Length: %zd\r\n" + "Server: Webdis\r\n" + "\r\n", code, msg, ct, body_len); + + if(!out) { + sz = ret + body_len; + out = malloc(sz); + } else { + if(body && body_len) memcpy(out + ret, body, body_len); + break; + } + } + + ok = write(c->fd, out, sz); + if(!ok) { + http_client_free(c); + } + free(out); +} + +void +http_set_header(str_t *h, const char *p) { + + h->s = strdup(p); + h->sz = strlen(p); +} diff --git a/http.h b/http.h index a307277..b59663a 100644 --- a/http.h +++ b/http.h @@ -29,6 +29,9 @@ struct http_client { str_t path; str_t body; + + str_t out_content_type; + str_t out_etag; }; struct http_client * @@ -49,4 +52,10 @@ http_on_path(http_parser*, const char *at, size_t length); int http_on_body(http_parser*, const char *at, size_t length); +int +http_on_complete(http_parser*); + +void +http_set_header(str_t *h, const char *p); + #endif