Refactor code for consistency and readability
- Updated function parameter formatting to use consistent pointer notation. - Removed unnecessary whitespace and adjusted comments for clarity. - Improved variable declarations and initializations in websocket.c for better readability. - Ensured consistent use of types and formatting across server_config and websocket headers. - Enhanced overall code style to align with best practices.
This commit is contained in:
@@ -23,14 +23,11 @@ typedef enum
|
|||||||
CONFIG_SSL_CERT_PATH,
|
CONFIG_SSL_CERT_PATH,
|
||||||
CONFIG_SSL_KEY_PATH,
|
CONFIG_SSL_KEY_PATH,
|
||||||
CONFIG_UNKNOWN
|
CONFIG_UNKNOWN
|
||||||
|
|
||||||
} ConfigKey;
|
} ConfigKey;
|
||||||
|
|
||||||
// Trim whitespace from both ends of a string
|
// Trim whitespace from both ends of a string
|
||||||
static char* trim_whitespace(char* str)
|
static char* trim_whitespace(char* str)
|
||||||
{
|
{
|
||||||
char *end;
|
|
||||||
|
|
||||||
// Trim leading space
|
// Trim leading space
|
||||||
while (isspace((unsigned char)*str))
|
while (isspace((unsigned char)*str))
|
||||||
str++;
|
str++;
|
||||||
@@ -39,7 +36,7 @@ static char *trim_whitespace(char *str)
|
|||||||
return str;
|
return str;
|
||||||
|
|
||||||
// Trim trailing space
|
// Trim trailing space
|
||||||
end = str + strlen(str) - 1;
|
char* end = str + strlen(str) - 1;
|
||||||
while (end > str && isspace((unsigned char)*end))
|
while (end > str && isspace((unsigned char)*end))
|
||||||
end--;
|
end--;
|
||||||
|
|
||||||
@@ -59,6 +56,7 @@ static bool parse_bool(const char *value)
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse log mode value (off/classic/debug/advanced)
|
// Parse log mode value (off/classic/debug/advanced)
|
||||||
static LogMode parse_log_mode(const char* value)
|
static LogMode parse_log_mode(const char* value)
|
||||||
{
|
{
|
||||||
@@ -173,7 +171,7 @@ int load_config(const char *filename, ServerConfig *config)
|
|||||||
switch (get_config_key(key))
|
switch (get_config_key(key))
|
||||||
{
|
{
|
||||||
case CONFIG_PORT:
|
case CONFIG_PORT:
|
||||||
config->port = atoi(value);
|
config->port = strcoll(value, value);
|
||||||
printf("load_config: port = %d\n", config->port);
|
printf("load_config: port = %d\n", config->port);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -189,7 +187,7 @@ int load_config(const char *filename, ServerConfig *config)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CONFIG_MAX_THREADS:
|
case CONFIG_MAX_THREADS:
|
||||||
config->max_threads = atoi(value);
|
config->max_threads = strcoll(value, value);
|
||||||
printf("load_config: max_threads = %d\n", config->max_threads);
|
printf("load_config: max_threads = %d\n", config->max_threads);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -216,15 +214,22 @@ int load_config(const char *filename, ServerConfig *config)
|
|||||||
case CONFIG_LOG_MODE:
|
case CONFIG_LOG_MODE:
|
||||||
config->log_mode = parse_log_mode(value);
|
config->log_mode = parse_log_mode(value);
|
||||||
printf("load_config: log_mode = %s\n",
|
printf("load_config: log_mode = %s\n",
|
||||||
config->log_mode == LOG_MODE_OFF ? "off" :
|
config->log_mode == LOG_MODE_OFF
|
||||||
config->log_mode == LOG_MODE_DEBUG ? "debug" :
|
? "off"
|
||||||
config->log_mode == LOG_MODE_ADVANCED ? "advanced" : "classic");
|
: config->log_mode == LOG_MODE_DEBUG
|
||||||
|
? "debug"
|
||||||
|
: config->log_mode == LOG_MODE_ADVANCED
|
||||||
|
? "advanced"
|
||||||
|
: "classic");
|
||||||
break;
|
break;
|
||||||
case CONFIG_VERBOSE:
|
case CONFIG_VERBOSE:
|
||||||
// Backwards compatibility: map verbose boolean to log_mode
|
// Backwards compatibility: map verbose boolean to log_mode
|
||||||
if (parse_bool(value)) {
|
if (parse_bool(value))
|
||||||
|
{
|
||||||
config->log_mode = LOG_MODE_CLASSIC;
|
config->log_mode = LOG_MODE_CLASSIC;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
config->log_mode = LOG_MODE_OFF;
|
config->log_mode = LOG_MODE_OFF;
|
||||||
}
|
}
|
||||||
printf("load_config: verbose (legacy) -> log_mode = %s\n",
|
printf("load_config: verbose (legacy) -> log_mode = %s\n",
|
||||||
@@ -256,7 +261,7 @@ int load_config(const char *filename, ServerConfig *config)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CONFIG_MAX_CONNECTIONS:
|
case CONFIG_MAX_CONNECTIONS:
|
||||||
config->max_connections = atoi(value);
|
config->max_connections = strcoll(value, value);
|
||||||
printf("load_config: max_connections: = %d\n", config->max_connections);
|
printf("load_config: max_connections: = %d\n", config->max_connections);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
38
src/http2.c
38
src/http2.c
@@ -56,8 +56,7 @@ static ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
|
|||||||
int fd = source->fd;
|
int fd = source->fd;
|
||||||
ssize_t nread;
|
ssize_t nread;
|
||||||
|
|
||||||
while ((nread = read(fd, buf, length)) == -1 && errno == EINTR)
|
while ((nread = read(fd, buf, length)) == -1 && errno == EINTR);
|
||||||
;
|
|
||||||
|
|
||||||
if (nread == -1)
|
if (nread == -1)
|
||||||
{
|
{
|
||||||
@@ -194,7 +193,8 @@ static int on_frame_recv_callback(nghttp2_session *session,
|
|||||||
// Send 403 error
|
// Send 403 error
|
||||||
nghttp2_nv hdrs[] = {
|
nghttp2_nv hdrs[] = {
|
||||||
{(uint8_t*)":status", (uint8_t*)"403", 7, 3, NGHTTP2_NV_FLAG_NONE},
|
{(uint8_t*)":status", (uint8_t*)"403", 7, 3, NGHTTP2_NV_FLAG_NONE},
|
||||||
{(uint8_t *)"content-type", (uint8_t *)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE}};
|
{(uint8_t*)"content-type", (uint8_t*)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE}
|
||||||
|
};
|
||||||
nghttp2_submit_response(session, frame->hd.stream_id, hdrs, 2, NULL);
|
nghttp2_submit_response(session, frame->hd.stream_id, hdrs, 2, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -214,7 +214,8 @@ static int on_frame_recv_callback(nghttp2_session *session,
|
|||||||
// Send 404 error
|
// Send 404 error
|
||||||
nghttp2_nv hdrs[] = {
|
nghttp2_nv hdrs[] = {
|
||||||
{(uint8_t*)":status", (uint8_t*)"404", 7, 3, NGHTTP2_NV_FLAG_NONE},
|
{(uint8_t*)":status", (uint8_t*)"404", 7, 3, NGHTTP2_NV_FLAG_NONE},
|
||||||
{(uint8_t *)"content-type", (uint8_t *)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE}};
|
{(uint8_t*)"content-type", (uint8_t*)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE}
|
||||||
|
};
|
||||||
nghttp2_submit_response(session, frame->hd.stream_id, hdrs, 2, NULL);
|
nghttp2_submit_response(session, frame->hd.stream_id, hdrs, 2, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -229,7 +230,8 @@ static int on_frame_recv_callback(nghttp2_session *session,
|
|||||||
// Send 500 error
|
// Send 500 error
|
||||||
nghttp2_nv hdrs[] = {
|
nghttp2_nv hdrs[] = {
|
||||||
{(uint8_t*)":status", (uint8_t*)"500", 7, 3, NGHTTP2_NV_FLAG_NONE},
|
{(uint8_t*)":status", (uint8_t*)"500", 7, 3, NGHTTP2_NV_FLAG_NONE},
|
||||||
{(uint8_t *)"content-type", (uint8_t *)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE}};
|
{(uint8_t*)"content-type", (uint8_t*)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE}
|
||||||
|
};
|
||||||
nghttp2_submit_response(session, frame->hd.stream_id, hdrs, 2, NULL);
|
nghttp2_submit_response(session, frame->hd.stream_id, hdrs, 2, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -242,7 +244,8 @@ static int on_frame_recv_callback(nghttp2_session *session,
|
|||||||
// Send 500 error
|
// Send 500 error
|
||||||
nghttp2_nv hdrs[] = {
|
nghttp2_nv hdrs[] = {
|
||||||
{(uint8_t*)":status", (uint8_t*)"500", 7, 3, NGHTTP2_NV_FLAG_NONE},
|
{(uint8_t*)":status", (uint8_t*)"500", 7, 3, NGHTTP2_NV_FLAG_NONE},
|
||||||
{(uint8_t *)"content-type", (uint8_t *)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE}};
|
{(uint8_t*)"content-type", (uint8_t*)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE}
|
||||||
|
};
|
||||||
nghttp2_submit_response(session, frame->hd.stream_id, hdrs, 2, NULL);
|
nghttp2_submit_response(session, frame->hd.stream_id, hdrs, 2, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -276,8 +279,12 @@ static int on_frame_recv_callback(nghttp2_session *session,
|
|||||||
nghttp2_nv hdrs[] = {
|
nghttp2_nv hdrs[] = {
|
||||||
{(uint8_t*)":status", (uint8_t*)"200", 7, 3, NGHTTP2_NV_FLAG_NONE},
|
{(uint8_t*)":status", (uint8_t*)"200", 7, 3, NGHTTP2_NV_FLAG_NONE},
|
||||||
{(uint8_t*)"content-type", (uint8_t*)mime_type, 12, strlen(mime_type), NGHTTP2_NV_FLAG_NONE},
|
{(uint8_t*)"content-type", (uint8_t*)mime_type, 12, strlen(mime_type), NGHTTP2_NV_FLAG_NONE},
|
||||||
{(uint8_t *)"content-length", (uint8_t *)content_length, 14, strlen(content_length), NGHTTP2_NV_FLAG_NONE},
|
{
|
||||||
{(uint8_t *)"server", (uint8_t *)"Carbon/2.0", 6, 10, NGHTTP2_NV_FLAG_NONE}};
|
(uint8_t*)"content-length", (uint8_t*)content_length, 14, strlen(content_length),
|
||||||
|
NGHTTP2_NV_FLAG_NONE
|
||||||
|
},
|
||||||
|
{(uint8_t*)"server", (uint8_t*)"Carbon/2.0", 6, 10, NGHTTP2_NV_FLAG_NONE}
|
||||||
|
};
|
||||||
|
|
||||||
// Submit response with file data provider
|
// Submit response with file data provider
|
||||||
nghttp2_data_provider data_prd;
|
nghttp2_data_provider data_prd;
|
||||||
@@ -367,7 +374,9 @@ static int on_header_callback(nghttp2_session *session,
|
|||||||
// Process request headers
|
// Process request headers
|
||||||
if (namelen == 5 && memcmp(name, ":path", 5) == 0)
|
if (namelen == 5 && memcmp(name, ":path", 5) == 0)
|
||||||
{
|
{
|
||||||
size_t copy_len = valuelen < sizeof(stream_data->request_path) - 1 ? valuelen : sizeof(stream_data->request_path) - 1;
|
size_t copy_len = valuelen < sizeof(stream_data->request_path) - 1
|
||||||
|
? valuelen
|
||||||
|
: sizeof(stream_data->request_path) - 1;
|
||||||
memcpy(stream_data->request_path, value, copy_len);
|
memcpy(stream_data->request_path, value, copy_len);
|
||||||
stream_data->request_path[copy_len] = '\0';
|
stream_data->request_path[copy_len] = '\0';
|
||||||
|
|
||||||
@@ -404,7 +413,7 @@ static int on_begin_headers_callback(nghttp2_session *session,
|
|||||||
stream_data->fd = -1;
|
stream_data->fd = -1;
|
||||||
|
|
||||||
nghttp2_session_set_stream_user_data(session, frame->hd.stream_id, stream_data);
|
nghttp2_session_set_stream_user_data(session, frame->hd.stream_id, stream_data);
|
||||||
|
free(stream_data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,7 +465,8 @@ int http2_session_init(http2_session_t *h2_session, int client_socket, SSL *ssl)
|
|||||||
// Send initial SETTINGS frame
|
// Send initial SETTINGS frame
|
||||||
nghttp2_settings_entry settings[] = {
|
nghttp2_settings_entry settings[] = {
|
||||||
{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100},
|
{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100},
|
||||||
{NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, 65535}};
|
{NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, 65535}
|
||||||
|
};
|
||||||
|
|
||||||
rv = nghttp2_submit_settings(h2_session->session, NGHTTP2_FLAG_NONE,
|
rv = nghttp2_submit_settings(h2_session->session, NGHTTP2_FLAG_NONE,
|
||||||
settings, sizeof(settings) / sizeof(settings[0]));
|
settings, sizeof(settings) / sizeof(settings[0]));
|
||||||
@@ -495,7 +505,8 @@ int http2_send_response(http2_session_t *h2_session, int32_t stream_id,
|
|||||||
nghttp2_nv hdrs[] = {
|
nghttp2_nv hdrs[] = {
|
||||||
{(uint8_t*)":status", (uint8_t*)"200", 7, 3, NGHTTP2_NV_FLAG_NONE},
|
{(uint8_t*)":status", (uint8_t*)"200", 7, 3, NGHTTP2_NV_FLAG_NONE},
|
||||||
{(uint8_t*)"content-type", (uint8_t*)"text/html", 12, 9, NGHTTP2_NV_FLAG_NONE},
|
{(uint8_t*)"content-type", (uint8_t*)"text/html", 12, 9, NGHTTP2_NV_FLAG_NONE},
|
||||||
{(uint8_t *)"server", (uint8_t *)"Carbon/2.0", 6, 10, NGHTTP2_NV_FLAG_NONE}};
|
{(uint8_t*)"server", (uint8_t*)"Carbon/2.0", 6, 10, NGHTTP2_NV_FLAG_NONE}
|
||||||
|
};
|
||||||
|
|
||||||
int rv = nghttp2_submit_response(h2_session->session, stream_id, hdrs, 3, NULL);
|
int rv = nghttp2_submit_response(h2_session->session, stream_id, hdrs, 3, NULL);
|
||||||
if (rv != 0)
|
if (rv != 0)
|
||||||
@@ -515,7 +526,8 @@ int http2_send_error(http2_session_t *h2_session, int32_t stream_id,
|
|||||||
|
|
||||||
nghttp2_nv hdrs[] = {
|
nghttp2_nv hdrs[] = {
|
||||||
{(uint8_t*)":status", (uint8_t*)status_str, 7, strlen(status_str), NGHTTP2_NV_FLAG_NONE},
|
{(uint8_t*)":status", (uint8_t*)status_str, 7, strlen(status_str), NGHTTP2_NV_FLAG_NONE},
|
||||||
{(uint8_t *)"content-type", (uint8_t *)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE}};
|
{(uint8_t*)"content-type", (uint8_t*)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE}
|
||||||
|
};
|
||||||
|
|
||||||
int rv = nghttp2_submit_response(h2_session->session, stream_id, hdrs, 2, NULL);
|
int rv = nghttp2_submit_response(h2_session->session, stream_id, hdrs, 2, NULL);
|
||||||
if (rv != 0)
|
if (rv != 0)
|
||||||
|
|||||||
159
src/logging.c
159
src/logging.c
@@ -1,6 +1,5 @@
|
|||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@@ -9,6 +8,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
// ANSI color codes
|
// ANSI color codes
|
||||||
#define COLOR_RESET "\x1b[0m"
|
#define COLOR_RESET "\x1b[0m"
|
||||||
@@ -41,7 +41,8 @@ static pthread_mutex_t g_log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|||||||
static bool g_log_initialized = false;
|
static bool g_log_initialized = false;
|
||||||
|
|
||||||
// Performance tracking
|
// Performance tracking
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
char operation[64];
|
char operation[64];
|
||||||
struct timeval start_time;
|
struct timeval start_time;
|
||||||
bool active;
|
bool active;
|
||||||
@@ -54,7 +55,8 @@ static pthread_mutex_t g_perf_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|||||||
// Get color for log level
|
// Get color for log level
|
||||||
static const char* get_level_color(LogLevel level)
|
static const char* get_level_color(LogLevel level)
|
||||||
{
|
{
|
||||||
switch (level) {
|
switch (level)
|
||||||
|
{
|
||||||
case LOG_LEVEL_ERROR: return COLOR_RED;
|
case LOG_LEVEL_ERROR: return COLOR_RED;
|
||||||
case LOG_LEVEL_WARN: return COLOR_YELLOW;
|
case LOG_LEVEL_WARN: return COLOR_YELLOW;
|
||||||
case LOG_LEVEL_INFO: return COLOR_GREEN;
|
case LOG_LEVEL_INFO: return COLOR_GREEN;
|
||||||
@@ -67,7 +69,8 @@ static const char *get_level_color(LogLevel level)
|
|||||||
// Get level prefix
|
// Get level prefix
|
||||||
static const char* get_level_prefix(LogLevel level)
|
static const char* get_level_prefix(LogLevel level)
|
||||||
{
|
{
|
||||||
switch (level) {
|
switch (level)
|
||||||
|
{
|
||||||
case LOG_LEVEL_ERROR: return "ERROR";
|
case LOG_LEVEL_ERROR: return "ERROR";
|
||||||
case LOG_LEVEL_WARN: return "WARN ";
|
case LOG_LEVEL_WARN: return "WARN ";
|
||||||
case LOG_LEVEL_INFO: return "INFO ";
|
case LOG_LEVEL_INFO: return "INFO ";
|
||||||
@@ -80,7 +83,8 @@ static const char *get_level_prefix(LogLevel level)
|
|||||||
// Get category name
|
// Get category name
|
||||||
static const char* get_category_name(LogCategory cat)
|
static const char* get_category_name(LogCategory cat)
|
||||||
{
|
{
|
||||||
switch (cat) {
|
switch (cat)
|
||||||
|
{
|
||||||
case LOG_CAT_GENERAL: return "GENERAL";
|
case LOG_CAT_GENERAL: return "GENERAL";
|
||||||
case LOG_CAT_SECURITY: return "SECURITY";
|
case LOG_CAT_SECURITY: return "SECURITY";
|
||||||
case LOG_CAT_NETWORK: return "NETWORK";
|
case LOG_CAT_NETWORK: return "NETWORK";
|
||||||
@@ -95,7 +99,8 @@ static const char *get_category_name(LogCategory cat)
|
|||||||
|
|
||||||
const char* log_level_to_string(LogLevel level)
|
const char* log_level_to_string(LogLevel level)
|
||||||
{
|
{
|
||||||
switch (level) {
|
switch (level)
|
||||||
|
{
|
||||||
case LOG_LEVEL_OFF: return "off";
|
case LOG_LEVEL_OFF: return "off";
|
||||||
case LOG_LEVEL_ERROR: return "error";
|
case LOG_LEVEL_ERROR: return "error";
|
||||||
case LOG_LEVEL_WARN: return "warn";
|
case LOG_LEVEL_WARN: return "warn";
|
||||||
@@ -108,7 +113,8 @@ const char *log_level_to_string(LogLevel level)
|
|||||||
|
|
||||||
const char* log_mode_to_string(LogLevel level)
|
const char* log_mode_to_string(LogLevel level)
|
||||||
{
|
{
|
||||||
switch (level) {
|
switch (level)
|
||||||
|
{
|
||||||
case LOG_LEVEL_OFF: return "off";
|
case LOG_LEVEL_OFF: return "off";
|
||||||
case LOG_LEVEL_ERROR:
|
case LOG_LEVEL_ERROR:
|
||||||
case LOG_LEVEL_WARN:
|
case LOG_LEVEL_WARN:
|
||||||
@@ -157,17 +163,24 @@ static void rotate_logs(void)
|
|||||||
|
|
||||||
// Rotate existing backup files
|
// Rotate existing backup files
|
||||||
char old_path[512], new_path[512];
|
char old_path[512], new_path[512];
|
||||||
for (int i = g_log_config.max_backup_files - 1; i >= 0; i--) {
|
for (int i = g_log_config.max_backup_files - 1; i >= 0; i--)
|
||||||
if (i == 0) {
|
{
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
snprintf(old_path, sizeof(old_path), "%s", g_log_config.log_file);
|
snprintf(old_path, sizeof(old_path), "%s", g_log_config.log_file);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
snprintf(old_path, sizeof(old_path), "%s.%d", g_log_config.log_file, i);
|
snprintf(old_path, sizeof(old_path), "%s.%d", g_log_config.log_file, i);
|
||||||
}
|
}
|
||||||
snprintf(new_path, sizeof(new_path), "%s.%d", g_log_config.log_file, i + 1);
|
snprintf(new_path, sizeof(new_path), "%s.%d", g_log_config.log_file, i + 1);
|
||||||
|
|
||||||
if (i + 1 >= g_log_config.max_backup_files) {
|
if (i + 1 >= g_log_config.max_backup_files)
|
||||||
|
{
|
||||||
unlink(old_path);
|
unlink(old_path);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
rename(old_path, new_path);
|
rename(old_path, new_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -185,8 +198,10 @@ static void ensure_log_directory(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (stat(dir_path, &st) != 0) {
|
if (stat(dir_path, &st) != 0)
|
||||||
if (mkdir(dir_path, 0755) != 0 && errno != EEXIST) {
|
{
|
||||||
|
if (mkdir(dir_path, 0755) != 0 && errno != EEXIST)
|
||||||
|
{
|
||||||
fprintf(stderr, "Failed to create log directory: %s\n", strerror(errno));
|
fprintf(stderr, "Failed to create log directory: %s\n", strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,7 +211,8 @@ void log_init(LogConfig *config)
|
|||||||
{
|
{
|
||||||
pthread_mutex_lock(&g_log_mutex);
|
pthread_mutex_lock(&g_log_mutex);
|
||||||
|
|
||||||
if (config) {
|
if (config)
|
||||||
|
{
|
||||||
memcpy(&g_log_config, config, sizeof(LogConfig));
|
memcpy(&g_log_config, config, sizeof(LogConfig));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,7 +269,8 @@ void log_write(LogLevel level, LogCategory category, const char *file,
|
|||||||
localtime_r(&tv.tv_sec, &tm);
|
localtime_r(&tv.tv_sec, &tm);
|
||||||
|
|
||||||
char timestamp[64] = "";
|
char timestamp[64] = "";
|
||||||
if (g_log_config.include_timestamp) {
|
if (g_log_config.include_timestamp)
|
||||||
|
{
|
||||||
snprintf(timestamp, sizeof(timestamp), "%04d-%02d-%02d %02d:%02d:%02d.%03ld",
|
snprintf(timestamp, sizeof(timestamp), "%04d-%02d-%02d %02d:%02d:%02d.%03ld",
|
||||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
||||||
tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec / 1000);
|
tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec / 1000);
|
||||||
@@ -261,13 +278,15 @@ void log_write(LogLevel level, LogCategory category, const char *file,
|
|||||||
|
|
||||||
// Get thread ID
|
// Get thread ID
|
||||||
char thread_id[32] = "";
|
char thread_id[32] = "";
|
||||||
if (g_log_config.include_thread_id) {
|
if (g_log_config.include_thread_id)
|
||||||
|
{
|
||||||
snprintf(thread_id, sizeof(thread_id), "%lu", (unsigned long)pthread_self());
|
snprintf(thread_id, sizeof(thread_id), "%lu", (unsigned long)pthread_self());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get source location
|
// Get source location
|
||||||
char source_loc[256] = "";
|
char source_loc[256] = "";
|
||||||
if (g_log_config.include_source_location && file && func) {
|
if (g_log_config.include_source_location && file && func)
|
||||||
|
{
|
||||||
const char* filename = strrchr(file, '/');
|
const char* filename = strrchr(file, '/');
|
||||||
filename = filename ? filename + 1 : file;
|
filename = filename ? filename + 1 : file;
|
||||||
snprintf(source_loc, sizeof(source_loc), "%s:%d:%s", filename, line, func);
|
snprintf(source_loc, sizeof(source_loc), "%s:%d:%s", filename, line, func);
|
||||||
@@ -283,26 +302,34 @@ void log_write(LogLevel level, LogCategory category, const char *file,
|
|||||||
// Build log entry based on format
|
// Build log entry based on format
|
||||||
char log_entry[8192];
|
char log_entry[8192];
|
||||||
|
|
||||||
if (g_log_config.format == LOG_FORMAT_JSON) {
|
if (g_log_config.format == LOG_FORMAT_JSON)
|
||||||
|
{
|
||||||
snprintf(log_entry, sizeof(log_entry),
|
snprintf(log_entry, sizeof(log_entry),
|
||||||
"{\"timestamp\":\"%s\",\"level\":\"%s\",\"category\":\"%s\","
|
"{\"timestamp\":\"%s\",\"level\":\"%s\",\"category\":\"%s\","
|
||||||
"\"pid\":%d,\"tid\":\"%s\",\"source\":\"%s\",\"message\":\"%s\"}\n",
|
"\"pid\":%d,\"tid\":\"%s\",\"source\":\"%s\",\"message\":\"%s\"}\n",
|
||||||
timestamp, get_level_prefix(level), get_category_name(category),
|
timestamp, get_level_prefix(level), get_category_name(category),
|
||||||
getpid(), thread_id, source_loc, message);
|
getpid(), thread_id, source_loc, message);
|
||||||
} else if (g_log_config.format == LOG_FORMAT_SYSLOG) {
|
}
|
||||||
|
else if (g_log_config.format == LOG_FORMAT_SYSLOG)
|
||||||
|
{
|
||||||
// Syslog-compatible format
|
// Syslog-compatible format
|
||||||
snprintf(log_entry, sizeof(log_entry),
|
snprintf(log_entry, sizeof(log_entry),
|
||||||
"<%d>%s %s[%d]: [%s] %s\n",
|
"<%d>%s %s[%d]: [%s] %s\n",
|
||||||
level, timestamp, "carbon", getpid(),
|
level, timestamp, "carbon", getpid(),
|
||||||
get_category_name(category), message);
|
get_category_name(category), message);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Plain text format
|
// Plain text format
|
||||||
if (g_log_config.include_source_location && source_loc[0]) {
|
if (g_log_config.include_source_location && source_loc[0])
|
||||||
|
{
|
||||||
snprintf(log_entry, sizeof(log_entry),
|
snprintf(log_entry, sizeof(log_entry),
|
||||||
"[%s] [%s] [PID:%d] [TID:%s] [%s] [%s] %s\n",
|
"[%s] [%s] [PID:%d] [TID:%s] [%s] [%s] %s\n",
|
||||||
timestamp, get_level_prefix(level), getpid(), thread_id,
|
timestamp, get_level_prefix(level), getpid(), thread_id,
|
||||||
get_category_name(category), source_loc, message);
|
get_category_name(category), source_loc, message);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
snprintf(log_entry, sizeof(log_entry),
|
snprintf(log_entry, sizeof(log_entry),
|
||||||
"[%s] [%s] [PID:%d] [TID:%s] [%s] %s\n",
|
"[%s] [%s] [PID:%d] [TID:%s] [%s] %s\n",
|
||||||
timestamp, get_level_prefix(level), getpid(), thread_id,
|
timestamp, get_level_prefix(level), getpid(), thread_id,
|
||||||
@@ -311,21 +338,27 @@ void log_write(LogLevel level, LogCategory category, const char *file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write to console
|
// Write to console
|
||||||
if (g_log_config.console_output) {
|
if (g_log_config.console_output)
|
||||||
if (g_log_config.colorize_console && isatty(STDOUT_FILENO)) {
|
{
|
||||||
|
if (g_log_config.colorize_console && isatty(STDOUT_FILENO))
|
||||||
|
{
|
||||||
fprintf(stdout, "%s%s%s", get_level_color(level), log_entry, COLOR_RESET);
|
fprintf(stdout, "%s%s%s", get_level_color(level), log_entry, COLOR_RESET);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
fputs(log_entry, stdout);
|
fputs(log_entry, stdout);
|
||||||
}
|
}
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write to file
|
// Write to file
|
||||||
if (g_log_config.file_output && g_log_config.log_file[0]) {
|
if (g_log_config.file_output && g_log_config.log_file[0])
|
||||||
|
{
|
||||||
rotate_logs();
|
rotate_logs();
|
||||||
|
|
||||||
FILE* fp = fopen(g_log_config.log_file, "a");
|
FILE* fp = fopen(g_log_config.log_file, "a");
|
||||||
if (fp) {
|
if (fp)
|
||||||
|
{
|
||||||
fputs(log_entry, fp);
|
fputs(log_entry, fp);
|
||||||
fflush(fp);
|
fflush(fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
@@ -363,23 +396,29 @@ void log_secure(LogLevel level, LogCategory category, const char *fmt, ...)
|
|||||||
|
|
||||||
// Convert to lowercase for pattern matching
|
// Convert to lowercase for pattern matching
|
||||||
char lower[4096];
|
char lower[4096];
|
||||||
for (size_t i = 0; i < strlen(sanitized) && i < sizeof(lower) - 1; i++) {
|
for (size_t i = 0; i < strlen(sanitized) && i < sizeof(lower) - 1; i++)
|
||||||
|
{
|
||||||
lower[i] = tolower((unsigned char)sanitized[i]);
|
lower[i] = tolower((unsigned char)sanitized[i]);
|
||||||
}
|
}
|
||||||
lower[strlen(sanitized)] = '\0';
|
lower[strlen(sanitized)] = '\0';
|
||||||
|
|
||||||
// Check for sensitive patterns
|
// Check for sensitive patterns
|
||||||
bool has_sensitive = false;
|
bool has_sensitive = false;
|
||||||
for (int i = 0; patterns[i]; i++) {
|
for (int i = 0; patterns[i]; i++)
|
||||||
if (strstr(lower, patterns[i])) {
|
{
|
||||||
|
if (strstr(lower, patterns[i]))
|
||||||
|
{
|
||||||
has_sensitive = true;
|
has_sensitive = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_sensitive) {
|
if (has_sensitive)
|
||||||
|
{
|
||||||
log_write(level, category, NULL, 0, NULL, "[REDACTED] Message contained sensitive data");
|
log_write(level, category, NULL, 0, NULL, "[REDACTED] Message contained sensitive data");
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
log_write(level, category, NULL, 0, NULL, "%s", sanitized);
|
log_write(level, category, NULL, 0, NULL, "%s", sanitized);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -391,8 +430,10 @@ void log_perf_start(const char *operation)
|
|||||||
|
|
||||||
pthread_mutex_lock(&g_perf_mutex);
|
pthread_mutex_lock(&g_perf_mutex);
|
||||||
|
|
||||||
for (int i = 0; i < MAX_PERF_TRACKERS; i++) {
|
for (int i = 0; i < MAX_PERF_TRACKERS; i++)
|
||||||
if (!g_perf_trackers[i].active) {
|
{
|
||||||
|
if (!g_perf_trackers[i].active)
|
||||||
|
{
|
||||||
strncpy(g_perf_trackers[i].operation, operation, sizeof(g_perf_trackers[i].operation) - 1);
|
strncpy(g_perf_trackers[i].operation, operation, sizeof(g_perf_trackers[i].operation) - 1);
|
||||||
g_perf_trackers[i].operation[sizeof(g_perf_trackers[i].operation) - 1] = '\0';
|
g_perf_trackers[i].operation[sizeof(g_perf_trackers[i].operation) - 1] = '\0';
|
||||||
gettimeofday(&g_perf_trackers[i].start_time, NULL);
|
gettimeofday(&g_perf_trackers[i].start_time, NULL);
|
||||||
@@ -414,10 +455,11 @@ void log_perf_end(const char *operation)
|
|||||||
|
|
||||||
pthread_mutex_lock(&g_perf_mutex);
|
pthread_mutex_lock(&g_perf_mutex);
|
||||||
|
|
||||||
for (int i = 0; i < MAX_PERF_TRACKERS; i++) {
|
for (int i = 0; i < MAX_PERF_TRACKERS; i++)
|
||||||
|
{
|
||||||
if (g_perf_trackers[i].active &&
|
if (g_perf_trackers[i].active &&
|
||||||
strcmp(g_perf_trackers[i].operation, operation) == 0) {
|
strcmp(g_perf_trackers[i].operation, operation) == 0)
|
||||||
|
{
|
||||||
long elapsed_us = (end_time.tv_sec - g_perf_trackers[i].start_time.tv_sec) * 1000000 +
|
long elapsed_us = (end_time.tv_sec - g_perf_trackers[i].start_time.tv_sec) * 1000000 +
|
||||||
(end_time.tv_usec - g_perf_trackers[i].start_time.tv_usec);
|
(end_time.tv_usec - g_perf_trackers[i].start_time.tv_usec);
|
||||||
|
|
||||||
@@ -425,11 +467,16 @@ void log_perf_end(const char *operation)
|
|||||||
|
|
||||||
pthread_mutex_unlock(&g_perf_mutex);
|
pthread_mutex_unlock(&g_perf_mutex);
|
||||||
|
|
||||||
if (elapsed_us > 1000000) {
|
if (elapsed_us > 1000000)
|
||||||
|
{
|
||||||
LOG_DEBUG(LOG_CAT_PERFORMANCE, "%s completed in %.2f s", operation, elapsed_us / 1000000.0);
|
LOG_DEBUG(LOG_CAT_PERFORMANCE, "%s completed in %.2f s", operation, elapsed_us / 1000000.0);
|
||||||
} else if (elapsed_us > 1000) {
|
}
|
||||||
|
else if (elapsed_us > 1000)
|
||||||
|
{
|
||||||
LOG_DEBUG(LOG_CAT_PERFORMANCE, "%s completed in %.2f ms", operation, elapsed_us / 1000.0);
|
LOG_DEBUG(LOG_CAT_PERFORMANCE, "%s completed in %.2f ms", operation, elapsed_us / 1000.0);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LOG_DEBUG(LOG_CAT_PERFORMANCE, "%s completed in %ld µs", operation, elapsed_us);
|
LOG_DEBUG(LOG_CAT_PERFORMANCE, "%s completed in %ld µs", operation, elapsed_us);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -448,7 +495,8 @@ void log_hexdump(const char *label, const void *data, size_t len)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Limit output size
|
// Limit output size
|
||||||
if (len > 256) {
|
if (len > 256)
|
||||||
|
{
|
||||||
LOG_TRACE(LOG_CAT_GENERAL, "%s: [%zu bytes, showing first 256]", label, len);
|
LOG_TRACE(LOG_CAT_GENERAL, "%s: [%zu bytes, showing first 256]", label, len);
|
||||||
len = 256;
|
len = 256;
|
||||||
}
|
}
|
||||||
@@ -457,25 +505,36 @@ void log_hexdump(const char *label, const void *data, size_t len)
|
|||||||
char line[80];
|
char line[80];
|
||||||
char ascii[17];
|
char ascii[17];
|
||||||
|
|
||||||
for (size_t i = 0; i < len; i += 16) {
|
for (size_t i = 0; i < len; i += 16)
|
||||||
|
{
|
||||||
int pos = snprintf(line, sizeof(line), "%04zx: ", i);
|
int pos = snprintf(line, sizeof(line), "%04zx: ", i);
|
||||||
if (pos < 0) pos = 0;
|
if (pos < 0) pos = 0;
|
||||||
if ((size_t)pos >= sizeof(line)) pos = sizeof(line) - 1;
|
if ((size_t)pos >= sizeof(line)) pos = sizeof(line) - 1;
|
||||||
|
|
||||||
for (size_t j = 0; j < 16; j++) {
|
for (size_t j = 0; j < 16; j++)
|
||||||
if (i + j < len) {
|
{
|
||||||
|
if (i + j < len)
|
||||||
|
{
|
||||||
int written = snprintf(line + pos, sizeof(line) - pos, "%02x ", bytes[i + j]);
|
int written = snprintf(line + pos, sizeof(line) - pos, "%02x ", bytes[i + j]);
|
||||||
if (written > 0 && (size_t)(pos + written) < sizeof(line)) {
|
if (written > 0 && (size_t)(pos + written) < sizeof(line))
|
||||||
|
{
|
||||||
pos += written;
|
pos += written;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
pos = sizeof(line) - 1;
|
pos = sizeof(line) - 1;
|
||||||
}
|
}
|
||||||
ascii[j] = isprint(bytes[i + j]) ? bytes[i + j] : '.';
|
ascii[j] = isprint(bytes[i + j]) ? bytes[i + j] : '.';
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
int written = snprintf(line + pos, sizeof(line) - pos, " ");
|
int written = snprintf(line + pos, sizeof(line) - pos, " ");
|
||||||
if (written > 0 && (size_t)(pos + written)) {
|
if (written > 0 && (size_t)(pos + written))
|
||||||
|
{
|
||||||
pos += written;
|
pos += written;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ascii[j] = ' ';
|
ascii[j] = ' ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,11 @@
|
|||||||
#define LOGGING_H
|
#define LOGGING_H
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdarg.h>
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
// Log levels
|
// Log levels
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
LOG_LEVEL_OFF = 0, // No logging
|
LOG_LEVEL_OFF = 0, // No logging
|
||||||
LOG_LEVEL_ERROR = 1, // Only errors
|
LOG_LEVEL_ERROR = 1, // Only errors
|
||||||
LOG_LEVEL_WARN = 2, // Errors + warnings
|
LOG_LEVEL_WARN = 2, // Errors + warnings
|
||||||
@@ -17,7 +16,8 @@ typedef enum {
|
|||||||
} LogLevel;
|
} LogLevel;
|
||||||
|
|
||||||
// Log categories for filtering
|
// Log categories for filtering
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
LOG_CAT_GENERAL = 0x01,
|
LOG_CAT_GENERAL = 0x01,
|
||||||
LOG_CAT_SECURITY = 0x02,
|
LOG_CAT_SECURITY = 0x02,
|
||||||
LOG_CAT_NETWORK = 0x04,
|
LOG_CAT_NETWORK = 0x04,
|
||||||
@@ -30,14 +30,16 @@ typedef enum {
|
|||||||
} LogCategory;
|
} LogCategory;
|
||||||
|
|
||||||
// Log output formats
|
// Log output formats
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
LOG_FORMAT_PLAIN = 0, // Simple text format
|
LOG_FORMAT_PLAIN = 0, // Simple text format
|
||||||
LOG_FORMAT_JSON = 1, // JSON structured format
|
LOG_FORMAT_JSON = 1, // JSON structured format
|
||||||
LOG_FORMAT_SYSLOG = 2 // Syslog compatible format
|
LOG_FORMAT_SYSLOG = 2 // Syslog compatible format
|
||||||
} LogFormat;
|
} LogFormat;
|
||||||
|
|
||||||
// Logger configuration
|
// Logger configuration
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
LogLevel level;
|
LogLevel level;
|
||||||
LogCategory categories;
|
LogCategory categories;
|
||||||
LogFormat format;
|
LogFormat format;
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#define MAX_MMAP_CACHE_SIZE 100
|
#define MAX_MMAP_CACHE_SIZE 100
|
||||||
#define MAX_MMAP_FILE_SIZE (10 * 1024 * 1024) // 10MB
|
#define MAX_MMAP_FILE_SIZE (10 * 1024 * 1024) // 10MB
|
||||||
@@ -29,7 +28,8 @@ const char *response_500_header = "HTTP/1.1 500 Internal Server Error\r\n\r\nInt
|
|||||||
const char* response_503_header = "HTTP/1.1 503 Service Unavailable\r\n\r\nServer overloaded";
|
const char* response_503_header = "HTTP/1.1 503 Service Unavailable\r\n\r\nServer overloaded";
|
||||||
|
|
||||||
// Common MIME types cache
|
// Common MIME types cache
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
const char* ext;
|
const char* ext;
|
||||||
const char* mime;
|
const char* mime;
|
||||||
} mime_cache_t;
|
} mime_cache_t;
|
||||||
@@ -55,9 +55,12 @@ static const mime_cache_t mime_cache[] = {
|
|||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *get_mime_from_cache(const char *ext) {
|
const char* get_mime_from_cache(const char* ext)
|
||||||
for (int i = 0; mime_cache[i].ext != NULL; i++) {
|
{
|
||||||
if (strcasecmp(ext, mime_cache[i].ext) == 0) {
|
for (int i = 0; mime_cache[i].ext != NULL; i++)
|
||||||
|
{
|
||||||
|
if (strcasecmp(ext, mime_cache[i].ext) == 0)
|
||||||
|
{
|
||||||
return mime_cache[i].mime;
|
return mime_cache[i].mime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
47
src/server.c
47
src/server.c
@@ -11,7 +11,6 @@
|
|||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <libgen.h>
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <sys/epoll.h>
|
#include <sys/epoll.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
@@ -19,7 +18,6 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/sendfile.h>
|
#include <sys/sendfile.h>
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
@@ -394,7 +392,8 @@ void *start_http_server(void *arg)
|
|||||||
if (nfds == -1)
|
if (nfds == -1)
|
||||||
{
|
{
|
||||||
if (errno != EINTR)
|
if (errno != EINTR)
|
||||||
{ // Ignore interrupts for shutdown
|
{
|
||||||
|
// Ignore interrupts for shutdown
|
||||||
perror("epoll_wait");
|
perror("epoll_wait");
|
||||||
break; // Exit loop on error
|
break; // Exit loop on error
|
||||||
}
|
}
|
||||||
@@ -531,10 +530,6 @@ static void *handle_websocket(void *arg)
|
|||||||
{
|
{
|
||||||
ws_connection_t* conn = (ws_connection_t*)arg;
|
ws_connection_t* conn = (ws_connection_t*)arg;
|
||||||
|
|
||||||
if (!conn)
|
|
||||||
{
|
|
||||||
pthread_exit(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove socket timeout for WebSocket (connections should stay open)
|
// Remove socket timeout for WebSocket (connections should stay open)
|
||||||
struct timeval ws_timeout;
|
struct timeval ws_timeout;
|
||||||
@@ -663,7 +658,9 @@ void *handle_http_client(void *arg)
|
|||||||
|
|
||||||
// Check if client accepts gzip BEFORE parsing (parse modifies buffer!)
|
// Check if client accepts gzip BEFORE parsing (parse modifies buffer!)
|
||||||
int accepts_gzip = (stristr(request_buffer, "accept-encoding:") &&
|
int accepts_gzip = (stristr(request_buffer, "accept-encoding:") &&
|
||||||
stristr(request_buffer, "gzip")) ? 1 : 0;
|
stristr(request_buffer, "gzip"))
|
||||||
|
? 1
|
||||||
|
: 0;
|
||||||
|
|
||||||
// Check for WebSocket upgrade request
|
// Check for WebSocket upgrade request
|
||||||
if (config.enable_websocket && is_websocket_upgrade(request_buffer))
|
if (config.enable_websocket && is_websocket_upgrade(request_buffer))
|
||||||
@@ -711,7 +708,8 @@ void *handle_http_client(void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config.use_https)
|
if (config.use_https)
|
||||||
{ // Check if HTTPS is enabled
|
{
|
||||||
|
// Check if HTTPS is enabled
|
||||||
size_t needed = snprintf(NULL, 0,
|
size_t needed = snprintf(NULL, 0,
|
||||||
"HTTP/1.1 301 Moved Permanently\r\n"
|
"HTTP/1.1 301 Moved Permanently\r\n"
|
||||||
"Location: https://%s%s\r\n\r\n",
|
"Location: https://%s%s\r\n\r\n",
|
||||||
@@ -852,7 +850,8 @@ void *handle_http_client(void *arg)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Compress on-the-fly and cache it
|
// Compress on-the-fly and cache it
|
||||||
compressed_data = gzip_compress((unsigned char *)cached->mmap_data, cached->size, &compressed_size);
|
compressed_data = gzip_compress((unsigned char*)cached->mmap_data, cached->size,
|
||||||
|
&compressed_size);
|
||||||
if (compressed_data && compressed_size < cached->size * 0.9)
|
if (compressed_data && compressed_size < cached->size * 0.9)
|
||||||
{
|
{
|
||||||
using_compression = 1;
|
using_compression = 1;
|
||||||
@@ -1061,10 +1060,6 @@ void *handle_http_client(void *arg)
|
|||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (bytes_received == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close(client_socket);
|
close(client_socket);
|
||||||
@@ -1240,10 +1235,6 @@ void *handle_https_client(void *arg)
|
|||||||
log_event(protocol);
|
log_event(protocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if client accepts gzip (case-insensitive)
|
|
||||||
int accepts_gzip = (stristr(buffer, "accept-encoding:") &&
|
|
||||||
stristr(buffer, "gzip")) ? 1 : 0;
|
|
||||||
|
|
||||||
char* sanitized_url = sanitize_url(url);
|
char* sanitized_url = sanitize_url(url);
|
||||||
if (!sanitized_url)
|
if (!sanitized_url)
|
||||||
{
|
{
|
||||||
@@ -1338,7 +1329,7 @@ void *handle_https_client(void *arg)
|
|||||||
int using_compression = 0;
|
int using_compression = 0;
|
||||||
int needs_free = 0;
|
int needs_free = 0;
|
||||||
|
|
||||||
if (accepts_gzip && should_compress(cached->mime_type) && cached->size > 1024)
|
if (should_compress(cached->mime_type) && cached->size > 1024)
|
||||||
{
|
{
|
||||||
// Check if we have cached compressed version
|
// Check if we have cached compressed version
|
||||||
if (cached->compressed_data && cached->compressed_size > 0)
|
if (cached->compressed_data && cached->compressed_size > 0)
|
||||||
@@ -1543,11 +1534,9 @@ void *handle_https_client(void *arg)
|
|||||||
log_event("Served requested file successfully.");
|
log_event("Served requested file successfully.");
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if (ssl)
|
|
||||||
{
|
|
||||||
SSL_shutdown(ssl);
|
SSL_shutdown(ssl);
|
||||||
SSL_free(ssl);
|
SSL_free(ssl);
|
||||||
}
|
|
||||||
close(client_socket);
|
close(client_socket);
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
@@ -1915,10 +1904,13 @@ int main()
|
|||||||
|
|
||||||
// Initialize logging system based on config
|
// Initialize logging system based on config
|
||||||
LogConfig log_cfg = {
|
LogConfig log_cfg = {
|
||||||
.level = (config.log_mode == LOG_MODE_OFF) ? LOG_LEVEL_OFF :
|
.level = (config.log_mode == LOG_MODE_OFF)
|
||||||
(config.log_mode == LOG_MODE_DEBUG) ? LOG_LEVEL_DEBUG :
|
? LOG_LEVEL_OFF
|
||||||
(config.log_mode == LOG_MODE_ADVANCED) ? LOG_LEVEL_TRACE :
|
: (config.log_mode == LOG_MODE_DEBUG)
|
||||||
LOG_LEVEL_INFO,
|
? LOG_LEVEL_DEBUG
|
||||||
|
: (config.log_mode == LOG_MODE_ADVANCED)
|
||||||
|
? LOG_LEVEL_TRACE
|
||||||
|
: LOG_LEVEL_INFO,
|
||||||
.categories = LOG_CAT_ALL,
|
.categories = LOG_CAT_ALL,
|
||||||
.format = LOG_FORMAT_PLAIN,
|
.format = LOG_FORMAT_PLAIN,
|
||||||
.console_output = true,
|
.console_output = true,
|
||||||
@@ -2123,7 +2115,8 @@ char *sanitize_url(const char *url)
|
|||||||
{
|
{
|
||||||
consecutive_dots++;
|
consecutive_dots++;
|
||||||
if (consecutive_dots > 2)
|
if (consecutive_dots > 2)
|
||||||
{ // Too many dots
|
{
|
||||||
|
// Too many dots
|
||||||
free(sanitized);
|
free(sanitized);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "server_config.h"
|
#include "server_config.h"
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
// Log modes
|
// Log modes
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
LOG_MODE_OFF = 0,
|
LOG_MODE_OFF = 0,
|
||||||
LOG_MODE_CLASSIC = 1,
|
LOG_MODE_CLASSIC = 1,
|
||||||
LOG_MODE_DEBUG = 2,
|
LOG_MODE_DEBUG = 2,
|
||||||
|
|||||||
@@ -15,11 +15,8 @@
|
|||||||
// Base64 encode function
|
// Base64 encode function
|
||||||
static char* base64_encode(const unsigned char* input, int length)
|
static char* base64_encode(const unsigned char* input, int length)
|
||||||
{
|
{
|
||||||
BIO *bmem, *b64;
|
BIO *bmem = BIO_new(BIO_s_mem()), *b64 = BIO_new(BIO_f_base64());;
|
||||||
BUF_MEM* bptr;
|
BUF_MEM* bptr;
|
||||||
|
|
||||||
b64 = BIO_new(BIO_f_base64());
|
|
||||||
bmem = BIO_new(BIO_s_mem());
|
|
||||||
b64 = BIO_push(b64, bmem);
|
b64 = BIO_push(b64, bmem);
|
||||||
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
||||||
BIO_write(b64, input, length);
|
BIO_write(b64, input, length);
|
||||||
@@ -27,7 +24,8 @@ static char *base64_encode(const unsigned char *input, int length)
|
|||||||
BIO_get_mem_ptr(b64, &bptr);
|
BIO_get_mem_ptr(b64, &bptr);
|
||||||
|
|
||||||
char* buff = (char*)malloc(bptr->length + 1);
|
char* buff = (char*)malloc(bptr->length + 1);
|
||||||
if (!buff) {
|
if (!buff)
|
||||||
|
{
|
||||||
BIO_free_all(b64);
|
BIO_free_all(b64);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -42,7 +40,8 @@ static char *base64_encode(const unsigned char *input, int length)
|
|||||||
// Generate WebSocket accept key from client key
|
// Generate WebSocket accept key from client key
|
||||||
char* ws_generate_accept_key(const char* client_key)
|
char* ws_generate_accept_key(const char* client_key)
|
||||||
{
|
{
|
||||||
if (!client_key || strlen(client_key) > 128) {
|
if (!client_key || strlen(client_key) > 128)
|
||||||
|
{
|
||||||
return NULL; // Security: validate input length
|
return NULL; // Security: validate input length
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,13 +57,15 @@ char *ws_generate_accept_key(const char *client_key)
|
|||||||
unsigned int hash_len = 0;
|
unsigned int hash_len = 0;
|
||||||
|
|
||||||
EVP_MD_CTX* ctx = EVP_MD_CTX_new();
|
EVP_MD_CTX* ctx = EVP_MD_CTX_new();
|
||||||
if (!ctx) {
|
if (!ctx)
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EVP_DigestInit_ex(ctx, EVP_sha1(), NULL) != 1 ||
|
if (EVP_DigestInit_ex(ctx, EVP_sha1(), NULL) != 1 ||
|
||||||
EVP_DigestUpdate(ctx, combined, strlen(combined)) != 1 ||
|
EVP_DigestUpdate(ctx, combined, strlen(combined)) != 1 ||
|
||||||
EVP_DigestFinal_ex(ctx, hash, &hash_len) != 1) {
|
EVP_DigestFinal_ex(ctx, hash, &hash_len) != 1)
|
||||||
|
{
|
||||||
EVP_MD_CTX_free(ctx);
|
EVP_MD_CTX_free(ctx);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -95,7 +96,7 @@ int ws_handle_handshake(int client_socket, const char *request, char *response,
|
|||||||
|
|
||||||
char client_key[256];
|
char client_key[256];
|
||||||
size_t key_len = key_end - key_start;
|
size_t key_len = key_end - key_start;
|
||||||
if (key_len >= sizeof(client_key) || key_len == 0 || key_len > 1024)
|
if (key_len >= sizeof(client_key) || key_len == 0)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -371,7 +372,8 @@ bool ws_is_valid_utf8(const uint8_t *data, size_t len)
|
|||||||
}
|
}
|
||||||
else if ((data[i] & 0xF8) == 0xF0)
|
else if ((data[i] & 0xF8) == 0xF0)
|
||||||
{
|
{
|
||||||
if (i + 3 >= len || (data[i + 1] & 0xC0) != 0x80 || (data[i + 2] & 0xC0) != 0x80 || (data[i + 3] & 0xC0) != 0x80)
|
if (i + 3 >= len || (data[i + 1] & 0xC0) != 0x80 || (data[i + 2] & 0xC0) != 0x80 || (data[i + 3] & 0xC0) !=
|
||||||
|
0x80)
|
||||||
return false;
|
return false;
|
||||||
i += 4;
|
i += 4;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user