Start sending HTTP replies.

master
Nicolas Favre-Felix 14 years ago
parent 0dde1f589e
commit 89bb00f5ca

@ -6,7 +6,7 @@ HTTP_PARSER_OBJS=http-parser/http_parser.o
DEPS=$(FORMAT_OBJS) $(HIREDIS_OBJ) $(JANSSON_OBJ) $(HTTP_PARSER_OBJS) 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) 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 LDFLAGS=-levent
all: $(OUT) Makefile all: $(OUT) Makefile

33
cmd.c

@ -13,11 +13,11 @@
#include <ctype.h> #include <ctype.h>
struct cmd * 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)); struct cmd *c = calloc(1, sizeof(struct cmd));
c->rq = rq; c->client = client;
c->count = count; c->count = count;
c->argv = calloc(count, sizeof(char*)); 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 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) { 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; char *slash;
const char *p; const char *p;
int cmd_len; int cmd_len;
@ -104,17 +105,17 @@ cmd_run(struct server *s, struct evhttp_request *rq,
uri_len = qmark - uri; uri_len = qmark - uri;
} }
for(p = uri; p && p < uri + uri_len; param_count++) { 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 */ if(body && body_len) { /* PUT request */
param_count++; param_count++;
} }
cmd = cmd_new(rq, param_count); cmd = cmd_new(client, param_count);
/* parse URI parameters */ /* FIXME: parse URI parameters */
evhttp_parse_query(uri, &cmd->uri_params); /* evhttp_parse_query(uri, &cmd->uri_params); */
/* get output formatting function */ /* get output formatting function */
uri_len = cmd_select_format(cmd, uri, uri_len, &f_format); 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; 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)) { if(!acl_allow_command(cmd, s->cfg, rq)) {
return -1; return -1;
} }
*/
/* check if we have to split the connection */ /* FIXME:check if we have to split the connection */
/*
if(cmd_is_subscribe(cmd)) { if(cmd_is_subscribe(cmd)) {
struct pubsub_client *ps; struct pubsub_client *ps;
@ -147,6 +151,7 @@ cmd_run(struct server *s, struct evhttp_request *rq,
ps->rq = rq; ps->rq = rq;
evhttp_connection_set_closecb(rq->evcon, on_http_disconnect, ps); evhttp_connection_set_closecb(rq->evcon, on_http_disconnect, ps);
} }
*/
/* no args (e.g. INFO command) */ /* no args (e.g. INFO command) */
if(!slash) { if(!slash) {
@ -158,7 +163,7 @@ cmd_run(struct server *s, struct evhttp_request *rq,
const char *arg = p; const char *arg = p;
int arg_len; int arg_len;
char *next = strchr(arg, '/'); char *next = memchr(arg, '/', uri_len - (arg-p));
if(!next || next > uri + uri_len) { /* last argument */ if(!next || next > uri + uri_len) { /* last argument */
p = uri + uri_len; p = uri + uri_len;
arg_len = p - arg; 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) { TAILQ_FOREACH(kv, &cmd->uri_params, next) {
if(strcmp(kv->key, "type") == 0) { 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; break;
} }
} }
*/
return uri_len - ext_len - 1; return uri_len - ext_len - 1;
} }

@ -8,6 +8,7 @@
#include <evhttp.h> #include <evhttp.h>
struct evhttp_request; struct evhttp_request;
struct http_client;
struct server; struct server;
struct cmd; struct cmd;
@ -18,9 +19,7 @@ struct cmd {
int count; int count;
const char **argv; const char **argv;
size_t *argv_len; size_t *argv_len;
struct evhttp_request *rq; struct http_client *client;
struct evkeyvalq uri_params;
int started_responding; int started_responding;
@ -38,13 +37,13 @@ struct pubsub_client {
}; };
struct cmd * struct cmd *
cmd_new(struct evhttp_request *rq, int count); cmd_new(struct http_client *client, int count);
void void
cmd_free(struct cmd *c); cmd_free(struct cmd *c);
int 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 *uri, size_t uri_len,
const char *body, size_t body_len); const char *body, size_t body_len);

@ -1,8 +1,8 @@
#include "common.h" #include "common.h"
#include "cmd.h" #include "cmd.h"
#include "http.h"
#include "md5/md5.h" #include "md5/md5.h"
#include <evhttp.h>
#include <string.h> #include <string.h>
/* TODO: replace this with a faster hash function */ /* TODO: replace this with a faster hash function */
@ -31,13 +31,8 @@ char *etag_new(const char *p, size_t sz) {
void void
format_send_reply(struct cmd *cmd, const char *p, size_t sz, const char *content_type) { format_send_reply(struct cmd *cmd, const char *p, size_t sz, const char *content_type) {
struct evbuffer *body;
int free_cmd = 1; int free_cmd = 1;
/* send reply */
body = evbuffer_new();
evbuffer_add(body, p, sz);
if(cmd_is_subscribe(cmd)) { if(cmd_is_subscribe(cmd)) {
free_cmd = 0; free_cmd = 0;
@ -45,35 +40,36 @@ format_send_reply(struct cmd *cmd, const char *p, size_t sz, const char *content
/* start streaming */ /* start streaming */
if(cmd->started_responding == 0) { if(cmd->started_responding == 0) {
cmd->started_responding = 1; cmd->started_responding = 1;
evhttp_add_header(cmd->rq->output_headers, "Content-Type", http_set_header(&cmd->client->out_content_type, cmd->mime?cmd->mime:content_type);
cmd->mime?cmd->mime:content_type); /*FIXME:
evhttp_send_reply_start(cmd->rq, 200, "OK"); evhttp_send_reply_start(cmd->rq, 200, "OK");
*/
} }
evhttp_send_reply_chunk(cmd->rq, body); /*FIXME: evhttp_send_reply_chunk(cmd->rq, body); */
} else { } else {
/* compute ETag */ /* compute ETag */
char *etag = etag_new(p, sz); char *etag = etag_new(p, sz);
const char *if_none_match; const char *if_none_match;
/* FIXME */
#if 1
/* check If-None-Match */ /* check If-None-Match */
if((if_none_match = evhttp_find_header(cmd->rq->input_headers, "If-None-Match")) if(0 /*FIXME:(if_none_match = evhttp_find_header(cmd->rq->input_headers, "If-None-Match"))
&& strcmp(if_none_match, etag) == 0) { && strcmp(if_none_match, etag) == 0*/) {
/* SAME! send 304. */ /* SAME! send 304. */
evhttp_send_reply(cmd->rq, 304, "Not Modified", NULL); /* evhttp_send_reply(cmd->rq, 304, "Not Modified", NULL); */
} else { } else {
evhttp_add_header(cmd->rq->output_headers, "Content-Type", http_set_header(&cmd->client->out_content_type, cmd->mime?cmd->mime:content_type);
cmd->mime?cmd->mime:content_type); http_set_header(&cmd->client->out_etag, etag);
evhttp_add_header(cmd->rq->output_headers, "ETag", etag); http_send_reply(cmd->client, 200, "OK", p, sz);
evhttp_send_reply(cmd->rq, 200, "OK", body);
} }
#endif
free(etag); free(etag);
} }
/* cleanup */ /* cleanup */
evbuffer_free(body);
if(free_cmd) { if(free_cmd) {
evhttp_clear_headers(&cmd->uri_params); /*FIXME: evhttp_clear_headers(&cmd->uri_params); */
cmd_free(cmd); cmd_free(cmd);
} }
} }

@ -16,7 +16,7 @@ custom_type_reply(redisAsyncContext *c, void *r, void *privdata) {
int int_len; int int_len;
if(reply == NULL) { if(reply == NULL) {
evhttp_send_reply(cmd->rq, 404, "Not Found", NULL); /* FIXME: evhttp_send_reply(cmd->rq, 404, "Not Found", NULL); */
return; return;
} }
@ -39,7 +39,7 @@ custom_type_reply(redisAsyncContext *c, void *r, void *privdata) {
} }
/* couldn't make sense of what the client wanted. */ /* 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); cmd_free(cmd);
} }

@ -24,7 +24,7 @@ json_reply(redisAsyncContext *c, void *r, void *privdata) {
} }
if (reply == NULL) { if (reply == NULL) {
evhttp_send_reply(cmd->rq, 404, "Not Found", NULL); http_send_reply(cmd->client, 404, "Not Found", NULL, 0);
return; return;
} }
@ -107,7 +107,8 @@ json_string_output(json_t *j, struct cmd *cmd) {
char *json_reply = json_dumps(j, JSON_COMPACT); char *json_reply = json_dumps(j, JSON_COMPACT);
/* check for JSONP */ /* FIXME: check for JSONP */
#if 0
TAILQ_FOREACH(kv, &cmd->uri_params, next) { TAILQ_FOREACH(kv, &cmd->uri_params, next) {
if(strcmp(kv->key, "jsonp") == 0) { if(strcmp(kv->key, "jsonp") == 0) {
size_t json_len = strlen(json_reply); size_t json_len = strlen(json_reply);
@ -124,7 +125,7 @@ json_string_output(json_t *j, struct cmd *cmd) {
return ret; return ret;
} }
} }
#endif
return json_reply; return json_reply;
} }

@ -19,7 +19,9 @@ raw_reply(redisAsyncContext *c, void *r, void *privdata) {
(void)c; (void)c;
if (reply == NULL) { if (reply == NULL) {
/* FIXME
evhttp_send_reply(cmd->rq, 404, "Not Found", NULL); evhttp_send_reply(cmd->rq, 404, "Not Found", NULL);
*/
return; return;
} }

@ -1,5 +1,7 @@
#include "http.h" #include "http.h"
#include "server.h" #include "server.h"
#include "slog.h"
#include "cmd.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@ -14,6 +16,8 @@ http_client_new(int fd, struct server *s) {
c->settings.on_path = http_on_path; c->settings.on_path = http_on_path;
c->settings.on_body = http_on_body; c->settings.on_body = http_on_body;
c->settings.on_message_complete = http_on_complete;
http_parser_init(&c->parser, HTTP_REQUEST); http_parser_init(&c->parser, HTTP_REQUEST);
c->parser.data = c; c->parser.data = c;
@ -65,6 +69,7 @@ http_client_free(struct http_client *c) {
close(c->fd); close(c->fd);
free(c->buffer); free(c->buffer);
free((char*)c->out_content_type.s);
free(c); free(c);
} }
@ -103,3 +108,81 @@ http_on_body(http_parser *p, const char *at, size_t length) {
return 0; 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);
}

@ -29,6 +29,9 @@ struct http_client {
str_t path; str_t path;
str_t body; str_t body;
str_t out_content_type;
str_t out_etag;
}; };
struct http_client * struct http_client *
@ -49,4 +52,10 @@ http_on_path(http_parser*, const char *at, size_t length);
int int
http_on_body(http_parser*, const char *at, size_t length); 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 #endif

Loading…
Cancel
Save