More simplly to use

Signed-off-by: Jianhui Zhao <jianhuizhao329@gmail.com>
main
Jianhui Zhao 2018-07-21 16:41:19 +08:00
parent abd7dbb17a
commit 3b1d425d07
12 changed files with 153 additions and 218 deletions

View File

@ -21,12 +21,17 @@
#include <stdlib.h>
#include <unistd.h>
#include <uhttpd.h>
#include <string.h>
#include <libubox/ulog.h>
static void hello_action(struct uh_client *cl)
static int on_request(struct uh_client *cl)
{
const char *path = cl->get_path(cl);
int body_len = 0;
if (strcmp(path, "/hello"))
return UH_REQUEST_CONTINUE;
cl->send_header(cl, 200, "OK", -1);
cl->append_header(cl, "Myheader", "Hello");
cl->header_end(cl);
@ -39,6 +44,8 @@ static void hello_action(struct uh_client *cl)
cl->chunk_printf(cl, "<h1>VAR name: %s</h1>", cl->get_var(cl, "name"));
cl->chunk_printf(cl, "<h1>BODY:%s</h1>", cl->get_body(cl, &body_len));
cl->request_done(cl);
return UH_REQUEST_DONE;
}
static void usage(const char *prog)
@ -96,7 +103,7 @@ int main(int argc, char **argv)
ULOG_INFO("Listen on: %s *:%d\n", srv->ssl ? "https" : "http", port);
srv->add_action(srv, "/hello", hello_action);
srv->request_cb = on_request;
uloop_run();
done:

View File

@ -51,7 +51,11 @@ srv:set_error404_cb(function(cl, opt)
uh.request_done(cl)
end)
srv:add_action("/lua", function(cl, opt)
srv:set_request_cb(function(cl, opt)
if opt.path ~= "/hello" then
return uh.REQUEST_CONTINUE
end
uh.send_header(cl, 200, "OK", -1)
uh.append_header(cl, "Myheader", "Hello")
uh.header_end(cl)
@ -74,6 +78,8 @@ srv:add_action("/lua", function(cl, opt)
end
uh.request_done(cl)
return uh.REQUEST_DONE
end)
uloop.run()

View File

@ -21,10 +21,16 @@
#include <stdlib.h>
#include <unistd.h>
#include <uhttpd.h>
#include <string.h>
#include <libubox/ulog.h>
static void hello_action(struct uh_client *cl)
static int on_request(struct uh_client *cl)
{
const char *path = cl->get_path(cl);
if (strcmp(path, "/template.html"))
return UH_REQUEST_CONTINUE;
#if (UHTTPD_LUA_SUPPORT)
uh_template(cl);
#else
@ -34,6 +40,8 @@ static void hello_action(struct uh_client *cl)
cl->chunk_printf(cl, "<h1>Lua not enabled when compile</h1>");
cl->request_done(cl);
#endif
return UH_REQUEST_DONE;
}
static void usage(const char *prog)
@ -72,7 +80,7 @@ int main(int argc, char **argv)
if (!verbose)
ulog_threshold(LOG_ERR);
ULOG_INFO("libuhttpd version: %s\n", UHTTPD_VERSION_STRING);
uloop_init();
@ -91,12 +99,16 @@ int main(int argc, char **argv)
ULOG_INFO("Listen on: %s *:%d\n", srv->ssl ? "https" : "http", port);
srv->add_action(srv, "/template.html", hello_action);
srv->request_cb = on_request;
uloop_run();
done:
uloop_done();
srv->free(srv);
if (srv) {
srv->free(srv);
free(srv);
}
return 0;
}

View File

@ -13,7 +13,7 @@ find_package(Lua)
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${LIBUBOX_INCLUDE_DIR})
set(EXTRA_LIBS ${LIBUBOX_LIBRARY} dl)
set(SOURCE_FILES uhttpd.c client.c log.c utils.c file.c action.c)
set(SOURCE_FILES uhttpd.c client.c log.c utils.c file.c)
set(UHTTPD_SSL_SUPPORT_CONFIG 1)
option(UHTTPD_SSL_SUPPORT "SSL support" ON)
@ -60,7 +60,6 @@ install(
${CMAKE_CURRENT_BINARY_DIR}/config.h
${CMAKE_CURRENT_SOURCE_DIR}/uhttpd.h
${CMAKE_CURRENT_SOURCE_DIR}/client.h
${CMAKE_CURRENT_SOURCE_DIR}/action.h
DESTINATION
include/uhttpd
)

View File

@ -1,128 +0,0 @@
/*
* Copyright (C) 2017 Jianhui Zhao <jianhuizhao329@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include <stdlib.h>
#include "action.h"
#include "uhttpd.h"
#include "log.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;
a = calloc(1, sizeof(struct uh_action) + strlen(path) + 1);
if (!a) {
uh_log_err("calloc");
return -1;
}
if (strlen(path) > sizeof(a->path) - 1) {
uh_log_err("The given path is too long");
goto err;
}
a->avl.key = strcpy(a->path, path);
a->cb = cb;
avl_insert(&srv->actions, &a->avl);
return 0;
err:
free(a);
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) {
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 a ? true : false;
}
void uh_action_free(struct uh_server *srv)
{
struct uh_action *node, *tmp;
avl_remove_all_elements(&srv->actions, node, avl, tmp)
free(node);
}

View File

@ -1,39 +0,0 @@
/*
* Copyright (C) 2017 Jianhui Zhao <jianhuizhao329@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef _ACTION_H
#define _ACTION_H
#include "client.h"
typedef void (*action_cb_t)(struct uh_client *cl);
struct uh_action {
struct avl_node avl;
action_cb_t cb;
char path[0];
};
int uh_add_action(struct uh_server *srv, const char *path, action_cb_t cb);
bool handle_action_request(struct uh_client *cl, const char *path);
void uh_action_free(struct uh_server *srv);
#endif

View File

@ -148,16 +148,82 @@ static inline const char *client_get_header(struct uh_client *cl, const char *na
static inline const char *client_get_body(struct uh_client *cl, int *len)
{
*len = cl->dispatch.action.post_len;
return cl->dispatch.action.body;
*len = cl->dispatch.post_len;
return cl->dispatch.body;
}
static int post_post_data(struct uh_client *cl, const char *data, int len)
{
struct dispatch *d = &cl->dispatch;
d->post_len += len;
if (d->post_len > UH_POST_MAX_POST_SIZE)
goto err;
if (d->post_len > UH_POST_DATA_BUF_SIZE) {
d->body = realloc(d->body, UH_POST_MAX_POST_SIZE);
if (!d->body) {
cl->send_error(cl, 500, "Internal Server Error", "No memory");
return 0;
}
}
memcpy(d->body, data, len);
return len;
err:
cl->send_error(cl, 413, "Request Entity Too Large", NULL);
return 0;
}
static void post_post_done(struct uh_client *cl)
{
char *path = kvlist_get(&cl->request.url, "path");
if (cl->srv->request_cb(cl) == UH_REQUEST_DONE)
return;
if (handle_file_request(cl, path))
return;
if (cl->srv->error404_cb) {
cl->srv->error404_cb(cl);
return;
}
cl->send_error(cl, 404, "Not Found", "The requested PATH %s was not found on this server.", path);
}
static void post_data_free(struct uh_client *cl)
{
struct dispatch *d = &cl->dispatch;
free(d->body);
}
static void uh_handle_request(struct uh_client *cl)
{
char *path = kvlist_get(&cl->request.url, "path");
if (handle_action_request(cl, path))
return;
if (cl->srv->request_cb) {
struct dispatch *d = &cl->dispatch;
switch (cl->request.method) {
case UH_HTTP_MSG_GET:
if (cl->srv->request_cb(cl) == UH_REQUEST_DONE)
return;
break;
case UH_HTTP_MSG_POST:
d->post_data = post_post_data;
d->post_done = post_post_done;
d->free = post_data_free;
d->body = calloc(1, UH_POST_DATA_BUF_SIZE);
if (!d->body)
cl->send_error(cl, 500, "Internal Server Error", "No memory");
return;
default:
cl->send_error(cl, 400, "Bad Request", "Invalid Request");
return;
}
}
if (handle_file_request(cl, path))
return;
@ -188,6 +254,8 @@ static void dispatch_done(struct uh_client *cl)
{
if (cl->dispatch.free)
cl->dispatch.free(cl);
memset(&cl->dispatch, 0, sizeof(struct dispatch));
}
static inline int hdr_get_len(struct kvlist *kv, const void *data)
@ -340,13 +408,13 @@ static void client_poll_post_data(struct uh_client *cl)
if (!buf || !len)
break;
if (!d->data_send)
if (!d->post_data)
return;
cur_len = min(r->content_length, len);
if (cur_len) {
if (d->data_send)
cur_len = d->data_send(cl, buf, cur_len);
if (d->post_data)
cur_len = d->post_data(cl, buf, cur_len);
r->content_length -= cur_len;
ustream_consume(cl->us, cur_len);
@ -355,8 +423,8 @@ static void client_poll_post_data(struct uh_client *cl)
}
if (!r->content_length && cl->state != CLIENT_STATE_DONE) {
if (cl->dispatch.data_done)
cl->dispatch.data_done(cl);
if (cl->dispatch.post_done)
cl->dispatch.post_done(cl);
cl->state = CLIENT_STATE_DONE;
}

View File

@ -32,6 +32,14 @@
#define UHTTPD_CONNECTION_TIMEOUT 30
#define UH_POST_DATA_BUF_SIZE 1024
#define UH_POST_MAX_POST_SIZE 4096
enum request_status {
UH_REQUEST_DONE,
UH_REQUEST_CONTINUE
};
enum http_method {
UH_HTTP_MSG_GET,
UH_HTTP_MSG_POST,
@ -64,21 +72,17 @@ struct http_request {
struct uh_client;
struct dispatch {
int (*data_send)(struct uh_client *cl, const char *data, int len);
void (*data_done)(struct uh_client *cl);
int (*post_data)(struct uh_client *cl, const char *data, int len);
void (*post_done)(struct uh_client *cl);
void (*write_cb)(struct uh_client *cl);
void (*free)(struct uh_client *cl);
union {
struct {
int fd;
} file;
struct {
int post_len;
char *body;
struct uh_action *a;
} action;
};
struct {
int fd;
} file;
int post_len;
char *body;
};
struct uh_client {

View File

@ -114,17 +114,20 @@ static void lua_prepare_action_argument(struct uh_client *cl, lua_State *L)
add_all_header(cl, L);
}
static void lua_uh_action(struct uh_client *cl)
static int lua_uh_on_request(struct uh_client *cl)
{
struct uh_server *srv = cl->srv;
lua_State *L = srv->L;
struct lua_uh_server *lsrv = container_of(cl->srv, struct lua_uh_server, srv);
lua_State *L = cl->srv->L;
lua_getglobal(L, "__uh_action_cb");
lua_getfield(L, -1, cl->get_path(cl));
lua_getglobal(L, "__uh_request_cb");
lua_rawgeti(L, -1, lsrv->request_cb_ref);
lua_remove(L, -2);
lua_prepare_action_argument(cl, L);
lua_call(L, 2, 0);
lua_call(L, 2, 1);
return lua_tointeger(L, -1);
}
static int lua_uh_ssl_init(lua_State *L)
@ -144,18 +147,17 @@ static int lua_uh_ssl_init(lua_State *L)
return 0;
}
static int lua_uh_add_action(lua_State *L)
static int lua_uh_set_request_cb(lua_State *L)
{
struct lua_uh_server *lsrv = luaL_checkudata(L, 1, LUA_UH_SERVER_MT);
const char *path = luaL_checkstring(L, 2);
luaL_checktype(L, 3, LUA_TFUNCTION);
luaL_checktype(L, 2, LUA_TFUNCTION);
lua_getglobal(L, "__uh_action_cb");
lua_pushvalue(L, 3);
lua_setfield(L, -2, path);
lua_getglobal(L, "__uh_request_cb");
lua_pushvalue(L, 2);
lsrv->request_cb_ref = luaL_ref(L, -2);
lsrv->srv.add_action(&lsrv->srv, path, lua_uh_action);
lsrv->srv.request_cb = lua_uh_on_request;
return 0;
}
@ -220,7 +222,7 @@ static int lua_uh_server_free(lua_State *L)
static const luaL_Reg server_mt[] = {
{ "ssl_init", lua_uh_ssl_init },
{ "add_action", lua_uh_add_action },
{ "set_request_cb", lua_uh_set_request_cb },
{ "set_error404_cb", lua_uh_set_error404_cb },
{ "set_options", lua_uh_set_options },
{ "free", lua_uh_server_free },
@ -374,7 +376,7 @@ static const luaL_Reg uhttpd_fun[] = {
int luaopen_uhttpd(lua_State *L)
{
lua_newtable(L);
lua_setglobal(L, "__uh_action_cb");
lua_setglobal(L, "__uh_request_cb");
lua_newtable(L);
lua_setglobal(L, "__uh_error404_cb");
@ -401,5 +403,11 @@ int luaopen_uhttpd(lua_State *L)
lua_pushinteger(L, LOG_ERR);
lua_setfield(L, -2, "LOG_ERR");
lua_pushinteger(L, UH_REQUEST_DONE);
lua_setfield(L, -2, "REQUEST_DONE");
lua_pushinteger(L, UH_REQUEST_CONTINUE);
lua_setfield(L, -2, "REQUEST_CONTINUE");
return 1;
}

View File

@ -36,6 +36,7 @@
struct lua_uh_server {
struct uh_server srv;
int error404_cb_ref;
int request_cb_ref;
};
#endif

View File

@ -49,7 +49,6 @@ static void uh_server_free(struct uh_server *srv)
list_for_each_entry_safe(cl, tmp, &srv->clients, list)
cl->free(cl);
uh_action_free(srv);
uh_ssl_free();
free(srv->docroot);
free(srv->index_file);
@ -89,7 +88,6 @@ void uh_server_init(struct uh_server *srv, int sock)
srv->free = uh_server_free;
srv->set_docroot = uh_set_docroot;
srv->set_index_file = uh_set_index_file;
srv->add_action = uh_add_action;
#if (UHTTPD_SSL_SUPPORT)
srv->ssl_init = uh_ssl_init;

View File

@ -22,7 +22,6 @@
#include "config.h"
#include "client.h"
#include "action.h"
struct uh_server {
bool ssl;
@ -37,7 +36,7 @@ struct uh_server {
void (*set_docroot)(struct uh_server *srv, const char *docroot);
void (*set_index_file)(struct uh_server *srv, const char *index_file);
void (*error404_cb)(struct uh_client *cl);
int (*add_action)(struct uh_server *srv, const char *path, action_cb_t cb);
int (*request_cb)(struct uh_client *cl);
#if (UHTTPD_SSL_SUPPORT)
int (*ssl_init)(struct uh_server *srv, const char *key, const char *crt);