Rename main to server and add empty executable userctl
This commit is contained in:
153
src/server.c
Normal file
153
src/server.c
Normal file
@@ -0,0 +1,153 @@
|
||||
#include <microhttpd.h>
|
||||
#include <sha256.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <dirent.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
|
||||
|
||||
Noh_Arena temp;
|
||||
|
||||
#include "id_store.c"
|
||||
#include "library.c"
|
||||
|
||||
typedef struct {
|
||||
SV base_path;
|
||||
SV library_name;
|
||||
} Settings;
|
||||
|
||||
static enum MHD_Result send_response(struct MHD_Connection *connection, int status, SV message, bool xml) {
|
||||
struct MHD_Response *response = MHD_create_response_from_buffer(
|
||||
message.count, (void*)message.elems, MHD_RESPMEM_MUST_COPY);
|
||||
if (!response) return MHD_NO;
|
||||
|
||||
if (xml) MHD_add_response_header(response, "content-type", "application/xml");
|
||||
|
||||
enum MHD_Result ret = MHD_queue_response(connection, status, response);
|
||||
MHD_destroy_response(response);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static enum MHD_Result send_epub_file(struct MHD_Connection *connection, int file, size_t size) {
|
||||
struct MHD_Response *response = MHD_create_response_from_fd(size, file);
|
||||
if (!response) return MHD_NO;
|
||||
|
||||
MHD_add_response_header(response, "content-type", "application/epub+zip");
|
||||
|
||||
enum MHD_Result ret = MHD_queue_response(connection, 200, response);
|
||||
MHD_destroy_response(response);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#include "opds_handler.c"
|
||||
#include "get_handler.c"
|
||||
|
||||
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;
|
||||
|
||||
Settings settings = *(Settings*)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(""), false);
|
||||
|
||||
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(""), false);
|
||||
#endif
|
||||
|
||||
noh_log(NOH_INFO, "Authenticated as "Nsv_Fmt, Nsv_Arg(username));
|
||||
|
||||
if (strcmp(method, "GET") != 0) return send_response(connection, 405, sv(""), false);
|
||||
|
||||
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, settings, username);
|
||||
if (noh_sv_eq_ci(controller, sv("get"))) return handle_get(connection, url, settings, username);
|
||||
return send_response(connection, 404, sv(""), false);
|
||||
}
|
||||
|
||||
void show_usage(char *program_name, char *error) {
|
||||
noh_log(NOH_INFO, "Usage:");
|
||||
noh_log(NOH_INFO, "%s port library_path library_name", 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, " library_name: The name of the library shown as the title of each user's root folder.");
|
||||
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);
|
||||
|
||||
if (argc < 1) show_usage(program_name, "Library name not provided.");
|
||||
char *library_name = noh_shift_args(&argc, &argv);
|
||||
|
||||
Settings settings = {
|
||||
.base_path = sv(library_path),
|
||||
.library_name = sv(library_name),
|
||||
};
|
||||
|
||||
temp = noh_arena_init(1 MB);
|
||||
struct MHD_Daemon *server;
|
||||
|
||||
// Start the HTTP server
|
||||
server = MHD_start_daemon(
|
||||
MHD_USE_INTERNAL_POLLING_THREAD,
|
||||
port,
|
||||
NULL, NULL,
|
||||
&request_handler, &settings,
|
||||
MHD_OPTION_END);
|
||||
|
||||
if (!server) {
|
||||
noh_log(NOH_ERROR, "Failed to start server.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
noh_log(NOH_INFO, "Server is running on http://0.0.0.0:%d", port);
|
||||
|
||||
// Keep the server running
|
||||
getchar();
|
||||
|
||||
// Stop the server
|
||||
MHD_stop_daemon(server);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user