parent
70f5016e61
commit
ab0228ffa8
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
63
src/action.c
63
src/action.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
67
src/client.c
67
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);
|
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);
|
||||||
|
|
||||||
|
|
13
src/client.h
13
src/client.h
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue