From c9ac352bb4df19af6d23cb8c7733239c7abec33c Mon Sep 17 00:00:00 2001 From: Azreyo <58790873+Azreyo@users.noreply.github.com> Date: Thu, 2 Oct 2025 18:57:05 +0000 Subject: [PATCH] Refactor server configuration management - Removed old server configuration files (server.json, server.log, server_config.c, server_config.h). - Introduced a new configuration file (server.conf) with a more structured format. - Implemented a configuration parser (config_parser.c) to read and apply settings from server.conf. - Updated server logic to utilize the new configuration structure. - Enhanced logging functionality and added rate limiting features. - Improved error handling and security measures in request processing. --- Makefile | 8 +- README.md | 57 +++++++---- config_parser.c | 108 --------------------- server.conf | 23 +++++ server.json | 9 -- server.log | 0 src/config_parser.c | 125 +++++++++++++++++++++++++ server.c => src/server.c | 3 +- server_config.c => src/server_config.c | 0 server_config.h => src/server_config.h | 0 10 files changed, 192 insertions(+), 141 deletions(-) delete mode 100644 config_parser.c create mode 100644 server.conf delete mode 100644 server.json delete mode 100644 server.log create mode 100644 src/config_parser.c rename server.c => src/server.c (99%) rename server_config.c => src/server_config.c (100%) rename server_config.h => src/server_config.h (100%) diff --git a/Makefile b/Makefile index 37a5c4d..ecb4c6c 100644 --- a/Makefile +++ b/Makefile @@ -11,18 +11,18 @@ NC := \033[0m CC = gcc CFLAGS = -Wall -Wextra -O2 -D_GNU_SOURCE LDFLAGS = -pthread -LIBS = -lssl -lcrypto -lcjson -lmagic +LIBS = -lssl -lcrypto -lmagic # Source files and object files -SRCS = server.c config_parser.c server_config.c +SRCS = src/server.c src/config_parser.c src/server_config.c OBJS = $(SRCS:.c=.o) TARGET = server # Header files -HEADERS = server_config.h +HEADERS = src/server_config.h # Include directories -INCLUDES = -I/usr/include/cjson +INCLUDES = # Count total number of source files TOTAL_FILES := $(words $(SRCS)) diff --git a/README.md b/README.md index cb2ac4f..f27d517 100644 --- a/README.md +++ b/README.md @@ -137,27 +137,47 @@ openssl req -x509 -newkey rsa:2048 \ ### Server Configuration -Create or edit `server.json` in the project root: +Create or edit `server.conf` in the project root. Carbon uses a traditional Linux-style configuration format with `key = value` pairs: -```json -{ - "port": 8080, - "use_https": false, - "log_file": "log/server.log", - "max_threads": 4, - "running": true, - "server_name": "localhost", - "verbose": true -} +```conf +# Carbon Web Server Configuration File +# Lines starting with # are comments + +# Server listening port +port = 8080 + +# Enable HTTPS (requires valid certificates in certs/ directory) +use_https = false + +# Log file location +log_file = log/server.log + +# Maximum number of worker threads +max_threads = 4 + +# Server running state +running = true + +# Server name or IP address (used for logging and response headers) +server_name = localhost + +# Enable verbose logging +verbose = true ``` **Configuration Options:** - `port`: HTTP port (default: 8080) -- `use_https`: Enable HTTPS (requires SSL certificates) +- `use_https`: Enable HTTPS - accepts: true/false, yes/no, on/off, 1/0 (requires SSL certificates) - `log_file`: Path to log file - `max_threads`: Number of worker threads - `server_name`: Your domain or IP address -- `verbose`: Enable detailed logging +- `verbose`: Enable detailed logging - accepts: true/false, yes/no, on/off, 1/0 + +**Note:** Boolean values are flexible and accept multiple formats: +- True: `true`, `yes`, `on`, `1` +- False: `false`, `no`, `off`, `0` + +Values can optionally be quoted with single or double quotes. ### Directory Structure @@ -215,12 +235,13 @@ curl -k https://localhost:443 ``` Carbon/ -├── server.c # Main server implementation -├── server_config.c # Configuration management -├── server_config.h # Configuration headers -├── config_parser.c # JSON configuration parser +├── src/ +│ ├── server.c # Main server implementation +│ ├── server_config.c # Configuration management +│ ├── server_config.h # Configuration headers +│ └── config_parser.c # Configuration file parser ├── Makefile # Build configuration -├── server.json # Server configuration file +├── server.conf # Server configuration file (Linux-style) ├── README.md # This file ├── LICENSE # MIT License ├── certs/ # SSL certificates (create this) diff --git a/config_parser.c b/config_parser.c deleted file mode 100644 index 52d57f1..0000000 --- a/config_parser.c +++ /dev/null @@ -1,108 +0,0 @@ -#include -#include -#include -#include -#include "server_config.h" -#include - -int load_config(const char *filename, ServerConfig *config) { - FILE *fp = fopen(filename, "r"); - if (!fp) { - perror("Error opening config file"); - return 1; - } - - fseek(fp, 0, SEEK_END); - long file_size = ftell(fp); - fseek(fp, 0, SEEK_SET); - - char *buffer = malloc(file_size + 1); - if (!buffer) { - perror("Error allocating memory for config file"); - fclose(fp); - return 1; - } - - size_t items_read = fread(buffer, file_size, 1, fp); - fclose(fp); // Close file immediately after reading - - if (items_read != 1) { - perror("Error reading config file"); - free(buffer); - return 1; - } - - buffer[file_size] = '\0'; - - cJSON *root = cJSON_Parse(buffer); - free(buffer); // Free buffer after parsing - - if (!root) { - const char *error_ptr = cJSON_GetErrorPtr(); - if (error_ptr != NULL) { - fprintf(stderr, "Error before: %s\n", error_ptr); - } - return 1; - } - - cJSON *port = cJSON_GetObjectItemCaseSensitive(root, "port"); - if (cJSON_IsNumber(port)) { - config->port = port->valueint; - printf("load_config: port = %d\n", config->port); - } else { - fprintf(stderr, "load_config: port not found or not a number. Using default.\n"); - config->port = 80; - } - - cJSON *use_https = cJSON_GetObjectItemCaseSensitive(root, "use_https"); - if (cJSON_IsBool(use_https)) { - config->use_https = cJSON_IsTrue(use_https); - printf("load_config: use_https = %d\n", config->use_https); - } else { - fprintf(stderr, "load_config: use_https not found or not a boolean. Using default.\n"); - config->use_https = false; - } - - cJSON *log_file = cJSON_GetObjectItemCaseSensitive(root, "log_file"); - if (cJSON_IsString(log_file) && (log_file->valuestring != NULL)) { - strncpy(config->log_file, log_file->valuestring, sizeof(config->log_file) - 1); - config->log_file[sizeof(config->log_file) - 1] = '\0'; - printf("load_config: log_file = %s\n", config->log_file); - } else { - fprintf(stderr, "load_config: log_file not found or not a string. Using default.\n"); - strcpy(config->log_file, "server.log"); - } - - cJSON *max_threads = cJSON_GetObjectItemCaseSensitive(root, "max_threads"); - if (cJSON_IsNumber(max_threads)) { - config->max_threads = max_threads->valueint; - printf("load_config: max_threads = %d\n", config->max_threads); - } else { - fprintf(stderr, "load_config: max_threads not found or not a number. Using default.\n"); - config->max_threads = 4; - } - - cJSON *running = cJSON_GetObjectItemCaseSensitive(root, "running"); - if (cJSON_IsBool(running)) { - config->running = cJSON_IsTrue(running); - printf("load_config: running = %d\n", config->running); - } else { - fprintf(stderr, "load_config: running not found or not a boolean. Using default.\n"); - config->running = true; - } - - cJSON *server_name = cJSON_GetObjectItemCaseSensitive(root, "server_name"); - if (cJSON_IsString(server_name) && (server_name->valuestring != NULL)) { - strncpy(config->server_name, server_name->valuestring, sizeof(config->server_name) - 1); - config->server_name[sizeof(config->server_name) - 1] = '\0'; - printf("load_config: server_name = %s\n", config->server_name); - if (strcmp(config->server_name, "Your_domain/IP") == 0) { - fprintf(stderr, "WARNING: server_name is set to 127.0.0.1\nPlease set server_name in server.json to the server's IP address or domain name for proper operation.\n"); - } - } else { - fprintf(stderr, "load_config: server_name not found or not a string. Using default.\n"); - strcpy(config->server_name, "127.0.0.1"); - } - cJSON_Delete(root); - return 0; -} diff --git a/server.conf b/server.conf new file mode 100644 index 0000000..9a44e83 --- /dev/null +++ b/server.conf @@ -0,0 +1,23 @@ +# Carbon Web Server Configuration File +# Lines starting with # are comments + +# Server listening port +port = 8080 + +# Enable HTTPS (requires valid certificates in certs/ directory) +use_https = false + +# Log file location +log_file = log/server.log + +# Maximum number of worker threads +max_threads = 4 + +# Server running state +running = true + +# Server name or IP address (used for logging and response headers) +server_name = 10.0.0.206 + +# Enable verbose logging +verbose = true diff --git a/server.json b/server.json deleted file mode 100644 index 7b55906..0000000 --- a/server.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "port": 8080, - "use_https": false, - "log_file": "log/server.log", - "max_threads": 4, - "running": true, - "server_name": "Your_domain/IP", - "verbose": true - } diff --git a/server.log b/server.log deleted file mode 100644 index e69de29..0000000 diff --git a/src/config_parser.c b/src/config_parser.c new file mode 100644 index 0000000..d3296be --- /dev/null +++ b/src/config_parser.c @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#include +#include "server_config.h" + +// Trim whitespace from both ends of a string +static char* trim_whitespace(char *str) { + char *end; + + // Trim leading space + while(isspace((unsigned char)*str)) str++; + + if(*str == 0) return str; + + // Trim trailing space + end = str + strlen(str) - 1; + while(end > str && isspace((unsigned char)*end)) end--; + + end[1] = '\0'; + return str; +} + +// Parse a boolean value (true/false, yes/no, on/off, 1/0) +static bool parse_bool(const char *value) { + if (strcasecmp(value, "true") == 0 || + strcasecmp(value, "yes") == 0 || + strcasecmp(value, "on") == 0 || + strcmp(value, "1") == 0) { + return true; + } + return false; +} + +int load_config(const char *filename, ServerConfig *config) { + FILE *fp = fopen(filename, "r"); + if (!fp) { + perror("Error opening config file"); + return 1; + } + + char line[512]; + int line_number = 0; + + while (fgets(line, sizeof(line), fp)) { + line_number++; + + // Remove newline + line[strcspn(line, "\r\n")] = 0; + + // Trim whitespace + char *trimmed = trim_whitespace(line); + + // Skip empty lines and comments + if (trimmed[0] == '\0' || trimmed[0] == '#' || trimmed[0] == ';') { + continue; + } + + // Find the delimiter (= or space) + char *delim = strchr(trimmed, '='); + if (!delim) { + // Try space as delimiter + delim = strchr(trimmed, ' '); + } + + if (!delim) { + fprintf(stderr, "Warning: Invalid config line %d: %s\n", line_number, trimmed); + continue; + } + + // Split into key and value + *delim = '\0'; + char *key = trim_whitespace(trimmed); + char *value = trim_whitespace(delim + 1); + + // Remove quotes from value if present + if ((value[0] == '"' || value[0] == '\'') && + value[strlen(value) - 1] == value[0]) { + value[strlen(value) - 1] = '\0'; + value++; + } + + // Parse configuration options + if (strcasecmp(key, "port") == 0) { + config->port = atoi(value); + printf("load_config: port = %d\n", config->port); + } + else if (strcasecmp(key, "use_https") == 0) { + config->use_https = parse_bool(value); + printf("load_config: use_https = %d\n", config->use_https); + } + else if (strcasecmp(key, "log_file") == 0) { + strncpy(config->log_file, value, sizeof(config->log_file) - 1); + config->log_file[sizeof(config->log_file) - 1] = '\0'; + printf("load_config: log_file = %s\n", config->log_file); + } + else if (strcasecmp(key, "max_threads") == 0) { + config->max_threads = atoi(value); + printf("load_config: max_threads = %d\n", config->max_threads); + } + else if (strcasecmp(key, "running") == 0) { + config->running = parse_bool(value); + printf("load_config: running = %d\n", config->running); + } + else if (strcasecmp(key, "server_name") == 0) { + strncpy(config->server_name, value, sizeof(config->server_name) - 1); + config->server_name[sizeof(config->server_name) - 1] = '\0'; + printf("load_config: server_name = %s\n", config->server_name); + if (strcmp(config->server_name, "Your_domain/IP") == 0) { + fprintf(stderr, "WARNING: server_name is set to default\nPlease set server_name in server.conf to the server's IP address or domain name for proper operation.\n"); + } + } + else if (strcasecmp(key, "verbose") == 0) { + config->verbose = parse_bool(value); + printf("load_config: verbose = %d\n", config->verbose); + } + else { + fprintf(stderr, "Warning: Unknown config option '%s' on line %d\n", key, line_number); + } + } + + fclose(fp); + return 0; +} diff --git a/server.c b/src/server.c similarity index 99% rename from server.c rename to src/server.c index 11f4a1b..efac524 100644 --- a/server.c +++ b/src/server.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -778,7 +777,7 @@ void signal_handler(int sig) { } int main() { - if (load_config("server.json", &config) != 0) { + if (load_config("server.conf", &config) != 0) { printf("Using default configuration.\n"); } diff --git a/server_config.c b/src/server_config.c similarity index 100% rename from server_config.c rename to src/server_config.c diff --git a/server_config.h b/src/server_config.h similarity index 100% rename from server_config.h rename to src/server_config.h