Files
FolderOpdsServer/src/main.c
2026-05-05 11:31:43 +02:00

136 lines
4.5 KiB
C

#include <microhttpd.h>
#include <sha256.h>
#define NOH_IMPLEMENTATION
#include "noh.h"
#define NO_AUTH
/* To disable Basic auth for testing:
#define NO_AUTH
This will ignore any auth headers and always log in with username demo.
*/
#define SV Noh_String_View
#define sv noh_sv_from_cstr
static enum MHD_Result send_response(struct MHD_Connection *connection, int status, SV message) {
struct MHD_Response *response = MHD_create_response_from_buffer(
message.count, (void*)message.elems, MHD_RESPMEM_PERSISTENT);
if (!response) return MHD_NO;
enum MHD_Result ret = MHD_queue_response(connection, status, response);
MHD_destroy_response(response);
return ret;
}
static enum MHD_Result handle_opds(struct MHD_Connection *connection, SV url, SV base_path, SV username) {
Noh_String fs_path = {0};
noh_string_append_sv(&fs_path, base_path);
noh_string_append_cstr(&fs_path, "/");
noh_string_append_sv(&fs_path, username);
noh_string_append_cstr(&fs_path, "/");
noh_string_append_sv(&fs_path, url);
noh_log(NOH_INFO, "Physical path: "Nsv_Fmt, Nsv_Arg(fs_path));
return send_response(connection, 200, sv("TODO: OPDS\n"));
}
static enum MHD_Result handle_get(struct MHD_Connection *connection, SV url, SV base_path, SV username) {
(void)url;
(void)username;
(void)base_path;
return send_response(connection, 200, sv("TODO: Get\n"));
}
bool is_slash(const char c) { return c == '/'; }
static enum MHD_Result request_handler(
void *cls,
struct MHD_Connection *connection,
const char *_url, const char *method, const char *version,
const char *upload_data, size_t *upload_data_size,
void **con_cls) {
(void)con_cls; (void)upload_data; (void)upload_data_size;
SV base_path = *(SV*)cls;
noh_log(NOH_INFO, "Request: %s %s %s", version, method, _url);
SV username;
#ifdef NO_AUTH
username = sv("demo");
#else
struct MHD_BasicAuthInfo *auth = MHD_basic_auth_get_username_password3(connection);
if (!auth) return send_response(connection, 401, sv(""));
username = (SV){ .elems = auth->username, .count = auth->username_len };
SV password = { .elems = auth->password, .count = auth->password_len };
// TODO: Read username from user config.
if (!noh_sv_eq(password, sv("jaja"))) return send_response(connection, 401, sv(""));
#endif
noh_log(NOH_INFO, "Authenticated as "Nsv_Fmt, Nsv_Arg(username));
if (strcmp(method, "GET") != 0) return send_response(connection, 405, sv(""));
SV url = sv(_url);
noh_sv_trim_left(&url, is_slash);
SV controller = noh_sv_chop_by_delim(&url, '/');
if (noh_sv_eq_ci(controller, sv("opds"))) return handle_opds(connection, url, base_path, username);
if (noh_sv_eq_ci(controller, sv("get"))) return handle_get(connection, url, base_path, username);
return send_response(connection, 404, sv(""));
}
void show_usage(char *program_name, char *error) {
noh_log(NOH_INFO, "Usage:");
noh_log(NOH_INFO, "%s port library_path", program_name);
noh_log(NOH_INFO, " port: The port to listen to, between 1000 and 65535.");
noh_log(NOH_INFO, " library_path: The path where the epub libraries are located.");
noh_log(NOH_INFO, " The root of this path should have a users.txt file with the usernames and passwords of valid users.");
noh_log(NOH_INFO, " For each user, ther must be a subdirectory where this user's library is located.");
noh_log(NOH_INFO, "");
noh_log(NOH_ERROR, "%s", error);
exit(1);
}
int main(int argc, char **argv)
{
// Parse input parameters.
char *program_name = noh_shift_args(&argc, &argv);
if (argc < 1) show_usage(program_name, "Port not provided.");
char *port_str = noh_shift_args(&argc, &argv);
int port = atoi(port_str);
if (port < 1000 || port > 65535) show_usage(program_name, "Invalid port.");
if (argc < 1) show_usage(program_name, "Library path not provided.");
char *library_path = noh_shift_args(&argc, &argv);
SV base_path = sv(library_path);
struct MHD_Daemon *server;
// Start the HTTP server
server = MHD_start_daemon(
MHD_USE_INTERNAL_POLLING_THREAD,
port,
NULL, NULL,
&request_handler, &base_path,
MHD_OPTION_END);
if (!server) {
fprintf(stderr, "Failed to start server\n");
return 1;
}
printf("Server is running on http://0.0.0.0:%d\n", port);
// Keep the server running
getchar();
// Stop the server
MHD_stop_daemon(server);
return 0;
}