Remove router code

This commit is contained in:
2025-04-20 21:21:54 +02:00
parent 6f634b8c8c
commit 579697f138
2 changed files with 1 additions and 356 deletions
+1 -341
View File
@@ -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
}