Files
c-relay/src/api.c

161 lines
5.0 KiB
C

// Define _GNU_SOURCE to ensure all POSIX features are available
#define _GNU_SOURCE
// API module for serving embedded web content and NIP-17 admin messaging
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <libwebsockets.h>
#include "api.h"
#include "embedded_web_content.h"
#include "config.h"
#include "debug.h"
// Forward declarations for database functions
int store_event(cJSON* event);
// Handle HTTP request for embedded files (assumes GET)
int handle_embedded_file_request(struct lws* wsi, const char* requested_uri) {
const char* file_path;
// Handle /api requests
char temp_path[256];
if (strcmp(requested_uri, "/api") == 0) {
// /api -> serve index.html
file_path = "/";
} else if (strncmp(requested_uri, "/api/", 5) == 0) {
// Extract file path from /api/ prefix and add leading slash for lookup
snprintf(temp_path, sizeof(temp_path), "/%s", requested_uri + 5); // Add leading slash
file_path = temp_path;
} else {
DEBUG_WARN("Embedded file request without /api prefix");
lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
return -1;
}
// Get embedded file
embedded_file_t* file = get_embedded_file(file_path);
if (!file) {
DEBUG_WARN("Embedded file not found");
lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
return -1;
}
// Allocate session data
struct embedded_file_session_data* session_data = malloc(sizeof(struct embedded_file_session_data));
if (!session_data) {
DEBUG_ERROR("Failed to allocate embedded file session data");
return -1;
}
session_data->type = 1; // Embedded file
session_data->data = file->data;
session_data->size = file->size;
session_data->content_type = file->content_type;
session_data->headers_sent = 0;
session_data->body_sent = 0;
// Store session data
lws_set_wsi_user(wsi, session_data);
// Prepare HTTP response headers
unsigned char buf[LWS_PRE + 1024];
unsigned char *p = &buf[LWS_PRE];
unsigned char *start = p;
unsigned char *end = &buf[sizeof(buf) - 1];
if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end)) {
free(session_data);
return -1;
}
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char*)file->content_type, strlen(file->content_type), &p, end)) {
free(session_data);
return -1;
}
if (lws_add_http_header_content_length(wsi, file->size, &p, end)) {
free(session_data);
return -1;
}
// Add CORS headers (same as NIP-11 for consistency)
if (lws_add_http_header_by_name(wsi, (unsigned char*)"access-control-allow-origin:", (unsigned char*)"*", 1, &p, end)) {
free(session_data);
return -1;
}
if (lws_add_http_header_by_name(wsi, (unsigned char*)"access-control-allow-headers:", (unsigned char*)"content-type, accept", 20, &p, end)) {
free(session_data);
return -1;
}
if (lws_add_http_header_by_name(wsi, (unsigned char*)"access-control-allow-methods:", (unsigned char*)"GET, OPTIONS", 12, &p, end)) {
free(session_data);
return -1;
}
// Add Connection: close to ensure connection closes after response
if (lws_add_http_header_by_name(wsi, (unsigned char*)"connection:", (unsigned char*)"close", 5, &p, end)) {
free(session_data);
return -1;
}
if (lws_finalize_http_header(wsi, &p, end)) {
free(session_data);
return -1;
}
// Write headers
if (lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS) < 0) {
free(session_data);
return -1;
}
session_data->headers_sent = 1;
// Request callback for body transmission
lws_callback_on_writable(wsi);
return 0;
}
// Handle HTTP_WRITEABLE for embedded files
int handle_embedded_file_writeable(struct lws* wsi) {
struct embedded_file_session_data* session_data = (struct embedded_file_session_data*)lws_wsi_user(wsi);
if (!session_data || session_data->headers_sent == 0 || session_data->body_sent == 1) {
return 0;
}
// Allocate buffer for data transmission
unsigned char *buf = malloc(LWS_PRE + session_data->size);
if (!buf) {
DEBUG_ERROR("Failed to allocate buffer for embedded file transmission");
free(session_data);
lws_set_wsi_user(wsi, NULL);
return -1;
}
// Copy data to buffer
memcpy(buf + LWS_PRE, session_data->data, session_data->size);
// Write data
int write_result = lws_write(wsi, buf + LWS_PRE, session_data->size, LWS_WRITE_HTTP);
// Free the transmission buffer
free(buf);
if (write_result < 0) {
DEBUG_ERROR("Failed to write embedded file data");
free(session_data);
lws_set_wsi_user(wsi, NULL);
return -1;
}
// Mark as sent and clean up
session_data->body_sent = 1;
free(session_data);
lws_set_wsi_user(wsi, NULL);
return 0;
}