Remove router code
This commit is contained in:
+1
-341
@@ -2603,344 +2603,4 @@ void tinyhttp_response_undo(TinyHTTPResponse res)
|
||||
return; // Invalid handle
|
||||
|
||||
tinyhttp_stream_response_undo(stream);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
// HTTP ROUTER //
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
#if TINYHTTP_ROUTER_ENABLE
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
typedef struct {
|
||||
char *ptr;
|
||||
int len;
|
||||
} string;
|
||||
|
||||
#define S(X) ((string) {(X), sizeof(X)-1})
|
||||
|
||||
typedef enum {
|
||||
ROUTE_STATIC_DIR,
|
||||
} RouteType;
|
||||
|
||||
typedef struct {
|
||||
RouteType type;
|
||||
string endpoint;
|
||||
string path;
|
||||
int dir_listing;
|
||||
} Route;
|
||||
|
||||
struct TinyHTTPRouter {
|
||||
int num_routes;
|
||||
int max_routes;
|
||||
Route routes[];
|
||||
};
|
||||
|
||||
TinyHTTPRouter *tinyhttp_router_init(void)
|
||||
{
|
||||
int max_routes = 32;
|
||||
TinyHTTPRouter *router = malloc(max_routes * sizeof(TinyHTTPRouter));
|
||||
if (router == NULL)
|
||||
return NULL;
|
||||
router->max_routes = max_routes;
|
||||
router->num_routes = 0;
|
||||
return router;
|
||||
}
|
||||
|
||||
void tinyhttp_router_free(TinyHTTPRouter *router)
|
||||
{
|
||||
free(router);
|
||||
}
|
||||
|
||||
void tinyhttp_router_dir(TinyHTTPRouter *router, string endpoint, string path, int dir_listing)
|
||||
{
|
||||
if (router->num_routes == router->max_routes)
|
||||
abort();
|
||||
Route *route = &router->routes[router->num_routes++];
|
||||
route->type = ROUTE_STATIC_DIR;
|
||||
route->endpoint = endpoint;
|
||||
route->path = path;
|
||||
route->dir_listing = dir_listing;
|
||||
}
|
||||
|
||||
static int
|
||||
valid_component_char(char c)
|
||||
{
|
||||
return is_alpha(c) || is_digit(c) || c == '-' || c == '_' || c == '.'; // TODO
|
||||
}
|
||||
|
||||
static int
|
||||
parse_path(string path, string *comps, int max_comps)
|
||||
{
|
||||
// We treat relative and absolute paths the same
|
||||
if (path.len > 0 && path.ptr[0] == '/') {
|
||||
path.ptr++;
|
||||
path.len--;
|
||||
if (path.len == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int num = 0;
|
||||
int cur = 0;
|
||||
for (;;) {
|
||||
if (cur == path.len || !valid_component_char(path.ptr[cur]))
|
||||
return -1; // Empty component
|
||||
int start = cur;
|
||||
do
|
||||
cur++;
|
||||
while (cur < path.len && valid_component_char(path.ptr[cur]));
|
||||
string comp = { path.ptr + start, cur - start };
|
||||
|
||||
if (eqstr(comp, S(".."))) {
|
||||
if (num == 0)
|
||||
return -1;
|
||||
num--;
|
||||
} else if (!eqstr(comp, S("."))) {
|
||||
if (num == max_comps)
|
||||
return -1;
|
||||
comps[num++] = comp;
|
||||
}
|
||||
|
||||
if (cur < path.len) {
|
||||
if (path.ptr[cur] != '/')
|
||||
return -1;
|
||||
cur++;
|
||||
}
|
||||
|
||||
if (cur == path.len)
|
||||
break;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static int swap_parents(string original_parent_path, string new_parent_path, string path, char *mem, int max)
|
||||
{
|
||||
int num_original_parent_path_comps;
|
||||
string original_parent_path_comps[TINYHTTP_ROUTER_MAX_PATH_COMPONENTS];
|
||||
|
||||
int num_new_parent_path_comps;
|
||||
string new_parent_path_comps[TINYHTTP_ROUTER_MAX_PATH_COMPONENTS];
|
||||
|
||||
int num_path_comps;
|
||||
string path_comps[TINYHTTP_ROUTER_MAX_PATH_COMPONENTS];
|
||||
|
||||
num_original_parent_path_comps = parse_path(original_parent_path, original_parent_path_comps, TINYHTTP_ROUTER_MAX_PATH_COMPONENTS);
|
||||
num_new_parent_path_comps = parse_path(new_parent_path, new_parent_path_comps, TINYHTTP_ROUTER_MAX_PATH_COMPONENTS);
|
||||
num_path_comps = parse_path(path, path_comps, TINYHTTP_ROUTER_MAX_PATH_COMPONENTS);
|
||||
if (num_original_parent_path_comps < 0 || num_new_parent_path_comps < 0 || num_path_comps < 0)
|
||||
return -1;
|
||||
|
||||
int match = 1;
|
||||
if (num_path_comps < num_original_parent_path_comps)
|
||||
match = 0;
|
||||
else {
|
||||
for (int i = 0; i < num_original_parent_path_comps; i++)
|
||||
if (!eqstr(original_parent_path_comps[i], path_comps[i])) {
|
||||
match = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!match)
|
||||
return 0;
|
||||
|
||||
int num_result_comps = num_new_parent_path_comps + num_path_comps - num_original_parent_path_comps;
|
||||
if (num_result_comps < 0 || num_result_comps > TINYHTTP_ROUTER_MAX_PATH_COMPONENTS)
|
||||
return -1;
|
||||
|
||||
string result_comps[TINYHTTP_ROUTER_MAX_PATH_COMPONENTS];
|
||||
for (int i = 0; i < num_new_parent_path_comps; i++)
|
||||
result_comps[i] = new_parent_path_comps[i];
|
||||
|
||||
for (int i = 0; i < num_path_comps; i++)
|
||||
result_comps[num_new_parent_path_comps + i] = path_comps[num_original_parent_path_comps + i];
|
||||
|
||||
int result_flat_len = 0;
|
||||
for (int i = 0; i < num_result_comps; i++)
|
||||
result_flat_len += result_comps[i].len + 1;
|
||||
|
||||
if (result_flat_len >= max)
|
||||
return -1;
|
||||
int copied = 0;
|
||||
for (int i = 0; i < num_result_comps; i++) {
|
||||
if (i > 0)
|
||||
mem[copied++] = '/';
|
||||
memcpy(mem + copied, result_comps[i].ptr, result_comps[i].len);
|
||||
copied += result_comps[i].len;
|
||||
}
|
||||
|
||||
mem[copied] = '\0';
|
||||
return result_flat_len;
|
||||
}
|
||||
|
||||
static void
|
||||
respond_with_regular_file(TinyHTTPServer *server, TinyHTTPResponse response, int fd, int file_size)
|
||||
{
|
||||
http_response_write_status(server, response, 200);
|
||||
|
||||
int cap;
|
||||
void *dst = http_response_write_body_ptr(server, response, file_size, &cap);
|
||||
if (dst) {
|
||||
int copied = 0;
|
||||
while (copied < file_size) {
|
||||
int ret = read(fd, dst + copied, file_size - copied);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
http_response_undo(server, response);
|
||||
http_response_write_status(server, response, 500);
|
||||
http_response_send(server, response);
|
||||
return;
|
||||
}
|
||||
if (ret == 0)
|
||||
break;
|
||||
copied += ret;
|
||||
}
|
||||
if (copied < file_size) {
|
||||
http_response_undo(server, response);
|
||||
http_response_write_status(server, response, 500);
|
||||
http_response_send(server, response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
http_response_write_body_ack(server, response, file_size);
|
||||
http_response_send(server, response);
|
||||
}
|
||||
|
||||
static void
|
||||
respond_with_dir_listing(TinyHTTPServer *server, TinyHTTPResponse response, DIR *dir)
|
||||
{
|
||||
http_response_write_status(server, response, 200);
|
||||
http_response_write_header(server, response, "Content-Type: text/html");
|
||||
http_response_write_body(server, response, S("<html><head></head><body><ul>"));
|
||||
struct dirent *entry;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
string name = { entry->d_name, strlen(entry->d_name) }; // TODO: Check that d_name is always zero terminated
|
||||
if (eqstr(name, S(".")) || eqstr(name, S("..")))
|
||||
continue;
|
||||
int cap;
|
||||
char *ptr = http_response_write_body_ptr(server, response, 128, &cap);
|
||||
int len = snprintf(ptr, cap, "<li><a href=''>%s</a></li>", entry->d_name); // TODO: add link
|
||||
if (len < 0 || len > cap) {
|
||||
// TODO
|
||||
}
|
||||
http_response_write_body_ack(server, response, len);
|
||||
}
|
||||
http_response_write_body(server, response, S("</ul></body></html>"));
|
||||
http_response_send(server, response);
|
||||
}
|
||||
|
||||
static int
|
||||
serve_static_dir(TinyHTTPServer *server, TinyHTTPResponse response, string base_endpoint, string base_path, string endpoint, int dir_listing)
|
||||
{
|
||||
char mem[1<<12];
|
||||
int res = swap_parents(base_endpoint, base_path, endpoint, mem, sizeof(mem));
|
||||
if (res <= 0)
|
||||
return res;
|
||||
string path = {mem, res}; // Note that this is zero terminated
|
||||
|
||||
int fd = open(path.ptr, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
http_response_write_status(server, response, 500);
|
||||
http_response_send(server, response);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct stat info;
|
||||
if (fstat(fd, &info) < 0) {
|
||||
http_response_write_status(server, response, 500);
|
||||
http_response_send(server, response);
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (S_ISDIR(info.st_mode)) {
|
||||
|
||||
int fd2 = openat(fd, "index.html", O_RDONLY);
|
||||
if (fd2 < 0) {
|
||||
if (errno != ENOENT) {
|
||||
http_response_write_status(server, response, 500);
|
||||
http_response_send(server, response);
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
// Allow falling through
|
||||
} else {
|
||||
|
||||
struct stat info2;
|
||||
if (fstat(fd2, &info2) < 0) {
|
||||
http_response_write_status(server, response, 500);
|
||||
http_response_send(server, response);
|
||||
close(fd2);
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
respond_with_regular_file(server, response, fd2, info2.st_size);
|
||||
|
||||
close(fd2);
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
// Allow falling through
|
||||
}
|
||||
|
||||
if (S_ISDIR(info.st_mode)) {
|
||||
|
||||
if (!dir_listing) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DIR *dir = fdopendir(fd);
|
||||
if (dir == NULL) {
|
||||
http_response_write_status(server, response, 500);
|
||||
http_response_send(server, response);
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
respond_with_dir_listing(server, response, dir);
|
||||
closedir(dir); // This also closes fd
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!S_ISREG(info.st_mode)) {
|
||||
http_response_write_status(server, response, 500);
|
||||
http_response_send(server, response);
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
int file_size = info.st_size;
|
||||
|
||||
respond_with_regular_file(server, response, fd, file_size);
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void http_router_resolve(TinyHTTPRouter *router, TinyHTTPServer *server, TinyHTTPRequest *request, TinyHTTPResponse response)
|
||||
{
|
||||
for (int i = 0; i < router->num_routes; i++) {
|
||||
Route *route = &router->routes[i];
|
||||
switch (route->type) {
|
||||
case ROUTE_STATIC_DIR:
|
||||
if (1 == serve_static_dir(server, response, route->endpoint, route->path, request->path, route->dir_listing))
|
||||
return;
|
||||
break;
|
||||
|
||||
default:
|
||||
http_response_write_status(server, response, 500);
|
||||
http_response_send(server, response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
http_response_write_status(server, response, 404);
|
||||
http_response_send(server, response);
|
||||
}
|
||||
|
||||
#endif // TINYHTTP_ROUTER_ENABLE
|
||||
}
|
||||
-15
@@ -31,9 +31,7 @@
|
||||
#include "tinyhttp_config.h"
|
||||
#else
|
||||
#define TINYHTTP_SERVER_ENABLE 1
|
||||
#define TINYHTTP_ROUTER_ENABLE 0
|
||||
#define TINYHTTP_HTTPS_ENABLE 0
|
||||
#define TINYHTTP_ROUTER_MAX_PATH_COMPONENTS 32
|
||||
#define TINYHTTP_HEADER_LIMIT 32
|
||||
#define TINYHTTP_SERVER_CONN_LIMIT (1<<10)
|
||||
#define TINYHTTP_SERVER_EPOLL_BATCH_SIZE (1<<10)
|
||||
@@ -46,7 +44,6 @@
|
||||
|
||||
// Opaque types
|
||||
typedef struct TinyHTTPServer TinyHTTPServer;
|
||||
typedef struct TinyHTTPRouter TinyHTTPRouter;
|
||||
|
||||
typedef struct {
|
||||
const char *ptr;
|
||||
@@ -346,15 +343,3 @@ void tinyhttp_response_send(TinyHTTPResponse res);
|
||||
|
||||
// TODO: Comment
|
||||
void tinyhttp_response_undo(TinyHTTPResponse res);
|
||||
|
||||
// TODO: Comment
|
||||
TinyHTTPRouter *tinyhttp_router_init(void);
|
||||
|
||||
// TODO: Comment
|
||||
void tinyhttp_router_free(TinyHTTPRouter *router);
|
||||
|
||||
// TODO: Comment
|
||||
void tinyhttp_router_resolve(TinyHTTPRouter *router, TinyHTTPServer *server, TinyHTTPRequest *request, TinyHTTPResponse response);
|
||||
|
||||
// TODO: Comment
|
||||
void tinyhttp_router_dir(TinyHTTPRouter *router, const char *endpoint, const char *path, int dir_listing);
|
||||
|
||||
Reference in New Issue
Block a user