Support parse POST data

Signed-off-by: Jianhui Zhao <jianhuizhao329@gmail.com>
main
Jianhui Zhao 2017-12-29 17:48:06 +08:00
parent 70f5016e61
commit ab0228ffa8
7 changed files with 136 additions and 15 deletions

View File

@ -55,6 +55,7 @@ Then use the command curl or browser to test
static void hello_action(struct uh_client *cl) static void hello_action(struct uh_client *cl)
{ {
int body_len = 0;
cl->send_header(cl, 200, "OK", -1); cl->send_header(cl, 200, "OK", -1);
cl->append_header(cl, "Myheader", "Hello"); cl->append_header(cl, "Myheader", "Hello");
cl->header_end(cl); cl->header_end(cl);
@ -63,6 +64,7 @@ static void hello_action(struct uh_client *cl)
cl->chunk_printf(cl, "<h1>REMOTE_ADDR: %s</h1>", cl->get_peer_addr(cl)); cl->chunk_printf(cl, "<h1>REMOTE_ADDR: %s</h1>", cl->get_peer_addr(cl));
cl->chunk_printf(cl, "<h1>PATH: %s</h1>", cl->get_path(cl)); cl->chunk_printf(cl, "<h1>PATH: %s</h1>", cl->get_path(cl));
cl->chunk_printf(cl, "<h1>QUERY: %s</h1>", cl->get_query(cl)); cl->chunk_printf(cl, "<h1>QUERY: %s</h1>", cl->get_query(cl));
cl->chunk_printf(cl, "<h1>BODY:%s</h1>", cl->get_body(cl, &body_len));
cl->request_done(cl); cl->request_done(cl);
} }

View File

@ -55,6 +55,7 @@
static void hello_action(struct uh_client *cl) static void hello_action(struct uh_client *cl)
{ {
int body_len = 0;
cl->send_header(cl, 200, "OK", -1); cl->send_header(cl, 200, "OK", -1);
cl->append_header(cl, "Myheader", "Hello"); cl->append_header(cl, "Myheader", "Hello");
cl->header_end(cl); cl->header_end(cl);
@ -63,6 +64,7 @@ static void hello_action(struct uh_client *cl)
cl->chunk_printf(cl, "<h1>REMOTE_ADDR: %s</h1>", cl->get_peer_addr(cl)); cl->chunk_printf(cl, "<h1>REMOTE_ADDR: %s</h1>", cl->get_peer_addr(cl));
cl->chunk_printf(cl, "<h1>PATH: %s</h1>", cl->get_path(cl)); cl->chunk_printf(cl, "<h1>PATH: %s</h1>", cl->get_path(cl));
cl->chunk_printf(cl, "<h1>QUERY: %s</h1>", cl->get_query(cl)); cl->chunk_printf(cl, "<h1>QUERY: %s</h1>", cl->get_query(cl));
cl->chunk_printf(cl, "<h1>BODY:%s</h1>", cl->get_body(cl, &body_len));
cl->request_done(cl); cl->request_done(cl);
} }

View File

@ -4,6 +4,8 @@
static void hello_action(struct uh_client *cl) static void hello_action(struct uh_client *cl)
{ {
int body_len = 0;
cl->send_header(cl, 200, "OK", -1); cl->send_header(cl, 200, "OK", -1);
cl->append_header(cl, "Myheader", "Hello"); cl->append_header(cl, "Myheader", "Hello");
cl->header_end(cl); cl->header_end(cl);
@ -12,6 +14,7 @@ static void hello_action(struct uh_client *cl)
cl->chunk_printf(cl, "<h1>REMOTE_ADDR: %s</h1>", cl->get_peer_addr(cl)); cl->chunk_printf(cl, "<h1>REMOTE_ADDR: %s</h1>", cl->get_peer_addr(cl));
cl->chunk_printf(cl, "<h1>PATH: %s</h1>", cl->get_path(cl)); cl->chunk_printf(cl, "<h1>PATH: %s</h1>", cl->get_path(cl));
cl->chunk_printf(cl, "<h1>QUERY: %s</h1>", cl->get_query(cl)); cl->chunk_printf(cl, "<h1>QUERY: %s</h1>", cl->get_query(cl));
cl->chunk_printf(cl, "<h1>BODY:%s</h1>", cl->get_body(cl, &body_len));
cl->request_done(cl); cl->request_done(cl);
} }

View File

@ -22,6 +22,9 @@
#include "action.h" #include "action.h"
#include "uhttpd.h" #include "uhttpd.h"
#define UH_ACTION_DATA_BUF_SIZE 1024
#define UH_ACTION_MAX_POST_SIZE 4096
int uh_add_action(struct uh_server *srv, const char *path, action_cb_t cb) int uh_add_action(struct uh_server *srv, const char *path, action_cb_t cb)
{ {
struct uh_action *a; struct uh_action *a;
@ -48,16 +51,70 @@ err:
return -1; return -1;
} }
static int action_data_send(struct uh_client *cl, const char *data, int len)
{
struct dispatch *d = &cl->dispatch;
d->action.post_len += len;
if (d->action.post_len > UH_ACTION_MAX_POST_SIZE)
goto err;
if (d->action.post_len > UH_ACTION_DATA_BUF_SIZE) {
d->action.body = realloc(d->action.body, UH_ACTION_MAX_POST_SIZE);
if (!d->action.body) {
cl->send_error(cl, 500, "Internal Server Error", "No memory");
return 0;
}
}
memcpy(d->action.body, data, len);
return len;
err:
cl->send_error(cl, 413, "Request Entity Too Large", NULL);
return 0;
}
static void action_data_done(struct uh_client *cl)
{
struct uh_action *a = cl->dispatch.action.a;
a->cb(cl);
}
static void action_data_free(struct uh_client *cl)
{
struct dispatch *d = &cl->dispatch;
free(d->action.body);
}
bool handle_action_request(struct uh_client *cl, const char *path) bool handle_action_request(struct uh_client *cl, const char *path)
{ {
struct dispatch *d = &cl->dispatch;
struct uh_action *a; struct uh_action *a;
a = avl_find_element(&cl->srv->actions, path, a, avl); a = avl_find_element(&cl->srv->actions, path, a, avl);
if (a) { if (a) {
a->cb(cl); switch (cl->request.method) {
return true; case UH_HTTP_MSG_POST:
d->action.a = a;
d->data_send = action_data_send;
d->data_done = action_data_done;
d->free = action_data_free;
d->action.body = calloc(1, UH_ACTION_DATA_BUF_SIZE);
if (!d->action.body)
cl->send_error(cl, 500, "Internal Server Error", "No memory");
break;
case UH_HTTP_MSG_GET:
a->cb(cl);
break;
default:
cl->send_error(cl, 400, "Bad Request", "Invalid Request");
break;
}
} }
return false;
return a ? true : false;
} }

View File

@ -101,6 +101,12 @@ static inline const char *client_get_header(struct uh_client *cl, const char *na
return kvlist_get(&cl->request.hdr, name); return kvlist_get(&cl->request.hdr, name);
} }
static inline const char *client_get_body(struct uh_client *cl, int *len)
{
*len = cl->dispatch.action.post_len;
return cl->dispatch.action.body;
}
static void uh_handle_request(struct uh_client *cl) static void uh_handle_request(struct uh_client *cl)
{ {
char *path = kvlist_get(&cl->request.hdr, "path"); char *path = kvlist_get(&cl->request.hdr, "path");
@ -138,8 +144,6 @@ static void dispatch_done(struct uh_client *cl)
{ {
if (cl->dispatch.free) if (cl->dispatch.free)
cl->dispatch.free(cl); cl->dispatch.free(cl);
if (cl->dispatch.req_free)
cl->dispatch.req_free(cl);
} }
static inline int hdr_get_len(struct kvlist *kv, const void *data) static inline int hdr_get_len(struct kvlist *kv, const void *data)
@ -256,13 +260,67 @@ static bool client_init_cb(struct uh_client *cl, char *buf, int len)
static void client_poll_post_data(struct uh_client *cl) static void client_poll_post_data(struct uh_client *cl)
{ {
struct dispatch *d = &cl->dispatch;
struct http_request *r = &cl->request; struct http_request *r = &cl->request;
char *buf;
int len;
if (cl->state == CLIENT_STATE_DONE) if (cl->state == CLIENT_STATE_DONE)
return; return;
if (!r->content_length && !r->transfer_chunked && while (1) {
cl->state != CLIENT_STATE_DONE) { char *sep;
int offset = 0;
int cur_len;
buf = ustream_get_read_buf(cl->us, &len);
if (!buf || !len)
break;
if (!d->data_send)
return;
cur_len = min(r->content_length, len);
if (cur_len) {
if (d->data_send)
cur_len = d->data_send(cl, buf, cur_len);
r->content_length -= cur_len;
ustream_consume(cl->us, cur_len);
continue;
}
if (!r->transfer_chunked)
break;
if (r->transfer_chunked > 1)
offset = 2;
sep = strstr(buf + offset, "\r\n");
if (!sep)
break;
*sep = 0;
r->content_length = strtoul(buf + offset, &sep, 16);
r->transfer_chunked++;
ustream_consume(cl->us, sep + 2 - buf);
/* invalid chunk length */
if (sep && *sep) {
r->content_length = 0;
r->transfer_chunked = 0;
break;
}
/* empty chunk == eof */
if (!r->content_length) {
r->transfer_chunked = false;
break;
}
}
if (!r->content_length && !r->transfer_chunked && cl->state != CLIENT_STATE_DONE) {
if (cl->dispatch.data_done) if (cl->dispatch.data_done)
cl->dispatch.data_done(cl); cl->dispatch.data_done(cl);
@ -462,6 +520,7 @@ void uh_accept_client(struct uh_server *srv, bool ssl)
cl->get_path = client_get_path; cl->get_path = client_get_path;
cl->get_query = client_get_query; cl->get_query = client_get_query;
cl->get_header = client_get_header; cl->get_header = client_get_header;
cl->get_body = client_get_body;
uh_log_debug("new connection: %s:%d", cl->get_peer_addr(cl), addr.sin_port); uh_log_debug("new connection: %s:%d", cl->get_peer_addr(cl), addr.sin_port);

View File

@ -61,19 +61,17 @@ struct dispatch {
int (*data_send)(struct uh_client *cl, const char *data, int len); int (*data_send)(struct uh_client *cl, const char *data, int len);
void (*data_done)(struct uh_client *cl); void (*data_done)(struct uh_client *cl);
void (*write_cb)(struct uh_client *cl); void (*write_cb)(struct uh_client *cl);
void (*close_fds)(struct uh_client *cl);
void (*free)(struct uh_client *cl); void (*free)(struct uh_client *cl);
void *req_data;
void (*req_free)(struct uh_client *cl);
bool data_blocked;
bool no_cache;
union { union {
struct { struct {
int fd; int fd;
} file; } file;
struct {
int post_len;
char *body;
struct uh_action *a;
} action;
}; };
}; };
@ -111,6 +109,7 @@ struct uh_client {
const char *(*get_path)(struct uh_client *cl); const char *(*get_path)(struct uh_client *cl);
const char *(*get_query)(struct uh_client *cl); const char *(*get_query)(struct uh_client *cl);
const char *(*get_header)(struct uh_client *cl, const char *name); const char *(*get_header)(struct uh_client *cl, const char *name);
const char *(*get_body)(struct uh_client *cl, int *len);
}; };
void uh_client_read_cb(struct uh_client *cl); void uh_client_read_cb(struct uh_client *cl);

View File

@ -370,7 +370,6 @@ static void uh_file_data(struct uh_client *cl, struct path_info *pi, int fd)
cl->dispatch.file.fd = fd; cl->dispatch.file.fd = fd;
cl->dispatch.write_cb = file_write_cb; cl->dispatch.write_cb = file_write_cb;
cl->dispatch.free = uh_file_free; cl->dispatch.free = uh_file_free;
cl->dispatch.close_fds = uh_file_free;
file_write_cb(cl); file_write_cb(cl);
} }