diff --git a/README.md b/README.md
index 711d7b5..2a2043b 100755
--- a/README.md
+++ b/README.md
@@ -55,6 +55,7 @@ Then use the command curl or browser to test
static void hello_action(struct uh_client *cl)
{
+ int body_len = 0;
cl->send_header(cl, 200, "OK", -1);
cl->append_header(cl, "Myheader", "Hello");
cl->header_end(cl);
@@ -63,6 +64,7 @@ static void hello_action(struct uh_client *cl)
cl->chunk_printf(cl, "
REMOTE_ADDR: %s
", cl->get_peer_addr(cl));
cl->chunk_printf(cl, "PATH: %s
", cl->get_path(cl));
cl->chunk_printf(cl, "QUERY: %s
", cl->get_query(cl));
+ cl->chunk_printf(cl, "BODY:%s
", cl->get_body(cl, &body_len));
cl->request_done(cl);
}
diff --git a/README_ZH.md b/README_ZH.md
index 9ebd428..64a164e 100755
--- a/README_ZH.md
+++ b/README_ZH.md
@@ -55,6 +55,7 @@
static void hello_action(struct uh_client *cl)
{
+ int body_len = 0;
cl->send_header(cl, 200, "OK", -1);
cl->append_header(cl, "Myheader", "Hello");
cl->header_end(cl);
@@ -63,6 +64,7 @@ static void hello_action(struct uh_client *cl)
cl->chunk_printf(cl, "REMOTE_ADDR: %s
", cl->get_peer_addr(cl));
cl->chunk_printf(cl, "PATH: %s
", cl->get_path(cl));
cl->chunk_printf(cl, "QUERY: %s
", cl->get_query(cl));
+ cl->chunk_printf(cl, "BODY:%s
", cl->get_body(cl, &body_len));
cl->request_done(cl);
}
diff --git a/example/helloworld.c b/example/helloworld.c
index 8a93c9f..2af166d 100755
--- a/example/helloworld.c
+++ b/example/helloworld.c
@@ -4,6 +4,8 @@
static void hello_action(struct uh_client *cl)
{
+ int body_len = 0;
+
cl->send_header(cl, 200, "OK", -1);
cl->append_header(cl, "Myheader", "Hello");
cl->header_end(cl);
@@ -12,6 +14,7 @@ static void hello_action(struct uh_client *cl)
cl->chunk_printf(cl, "REMOTE_ADDR: %s
", cl->get_peer_addr(cl));
cl->chunk_printf(cl, "PATH: %s
", cl->get_path(cl));
cl->chunk_printf(cl, "QUERY: %s
", cl->get_query(cl));
+ cl->chunk_printf(cl, "BODY:%s
", cl->get_body(cl, &body_len));
cl->request_done(cl);
}
diff --git a/src/action.c b/src/action.c
index 0925abb..81e052f 100755
--- a/src/action.c
+++ b/src/action.c
@@ -22,6 +22,9 @@
#include "action.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)
{
struct uh_action *a;
@@ -48,16 +51,70 @@ err:
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)
{
+ struct dispatch *d = &cl->dispatch;
struct uh_action *a;
a = avl_find_element(&cl->srv->actions, path, a, avl);
if (a) {
- a->cb(cl);
- return true;
+ switch (cl->request.method) {
+ 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;
}
diff --git a/src/client.c b/src/client.c
index 0265615..032483c 100755
--- a/src/client.c
+++ b/src/client.c
@@ -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);
}
+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)
{
char *path = kvlist_get(&cl->request.hdr, "path");
@@ -138,8 +144,6 @@ static void dispatch_done(struct uh_client *cl)
{
if (cl->dispatch.free)
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)
@@ -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)
{
+ struct dispatch *d = &cl->dispatch;
struct http_request *r = &cl->request;
+ char *buf;
+ int len;
if (cl->state == CLIENT_STATE_DONE)
return;
- if (!r->content_length && !r->transfer_chunked &&
- cl->state != CLIENT_STATE_DONE) {
+ while (1) {
+ 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)
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_query = client_get_query;
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);
diff --git a/src/client.h b/src/client.h
index dc09d72..1197314 100755
--- a/src/client.h
+++ b/src/client.h
@@ -61,19 +61,17 @@ struct dispatch {
int (*data_send)(struct uh_client *cl, const char *data, int len);
void (*data_done)(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 *req_data;
- void (*req_free)(struct uh_client *cl);
-
- bool data_blocked;
- bool no_cache;
-
union {
struct {
int fd;
} 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_query)(struct uh_client *cl);
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);
diff --git a/src/file.c b/src/file.c
index feaf890..3dab3df 100755
--- a/src/file.c
+++ b/src/file.c
@@ -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.write_cb = file_write_cb;
cl->dispatch.free = uh_file_free;
- cl->dispatch.close_fds = uh_file_free;
file_write_cb(cl);
}