Welcome to c-web-modules Documentation
Getting Started
c-web-modules is a proof-of-concept modular framework for web development in C. Inspired by kernel modules, it enables dynamic runtime compilation and deployment of C code directly to the server. No precompilation is required.
Server
The c-web-modules server is a simple web server that listens on port 8080. It provides the foundation for loading and executing modules at runtime. The server relies on the following libraries:
- openssl: For secure connections (planned) and hashing
- sqlite3: For database management
- jansson: For JSON parsing and manipulation
Check the Installation section for setup details. The easiest way to start the server is by using Docker.
Modules
Modules are dynamically loaded pieces of C code that define routes and WebSocket handlers. The most important part of the module is the module_t config.
For a module to be loaded into the server, the module needs to define a module_t struct with the name config. Preferbaly with the `export` macro. The module_t config struct defines the module name, author, routes, and WebSocket handlers. It also allows handlers to call when the module is loaded and unloaded.
/* Module information */
typedef struct module {
char name[128];
char author[128];
route_info_t routes[10];
int size;
websocket_info_t websockets[10];
int ws_size;
void (*onload)(void);
void (*unload)(void);
} module_t;
Check the Examples section for sample modules.
A route is defined by a path, method, function and flags. The path needs to be unique for the server, or else the module will not be loaded.
Websockets are defined by a path, on_open, on_message and on_close. Websocket connections will not be closed when a module is reloaded or changed. This needs to be done by the user.
Deployment
The most simple way to load a module is to use curl:
curl -X POST -d @path/to/module.c http://localhost:8080/mgnt
You can also deploy modules dynamically with configuration files:
./cweb deploy path/to/module.c
# Using a config file (routes.ini)
server_url=http://localhost:8080/mgnt
[modules]
example1.c
example2.c
Examples
#include <stdio.h>
#include <cweb.h>
static int counter = 0;
static const char* template =
"\n"
" \n"
" Counter: %d
\n"
" \n"
"\n";
/* Route: /counter - Method GET */
static int index_route(struct http_request *req, struct http_response *res) {
snprintf(res->body, HTTP_RESPONSE_SIZE, template, counter++);
res->status = HTTP_200_OK;
return 0;
}
/* Define the routes for the module */
export module_t config = {
.name = "counter",
.author = "cweb",
.routes = {
{"/counter", "GET", index_route, NONE},
},
.size = 1,
};
For more examples, check out the following links:
Installation
Install the required dependencies for Linux or MacOS:
For Debian:
- sudo apt-get install libssl-dev
- sudo apt-get install libsqlite3-dev
- sudo apt-get install libjansson-dev
For Arch Linux:
- sudo pacman -S openssl
- sudo pacman -S sqlite
- sudo pacman -S jansson
For MacOS:
- brew install openssl
- brew install sqlite3
- brew install jansson
Compile and run the server:
make
make run
WebSockets
WebSockets enable real-time communication between clients and the server. Here's an example module with WebSocket handlers:
#include
void on_open(struct websocket *ws) {
printf("WebSocket connection opened\n");
}
void on_message(struct websocket *ws, const char *message, size_t length) {
printf("Message received: %.*s\n", (int)length, message);
}
void on_close(struct websocket *ws) {
printf("WebSocket connection closed\n");
}
export module_t config = {
.name = "websocket_example",
.author = "cweb",
.websockets = {
{"/ws", on_open, on_message, on_close},
},
.ws_size = 1,
};
Environments
The c-web-modules framework supports multiple environments.
By default, the development environment is used, which uses HTTP. For production, the server uses HTTPS, which requires `server.crt` and `server.key` files. They can be generated using:
openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.crt -days 365 -nodes
Alternatively, you can use the `production.sh` script, which will also build the server with the `PRODUCTION` flag.
Production
To build the server for production, use the production.sh
script:
./production.sh
To build a Docker image for production, use the --docker
flag:
./production.sh --docker
This will create a cweb:production
Docker image that you can run with:
docker run -p 8080:8080 cweb:production
Key Structs
The following structs are central to the framework:
HTTP Request
struct http_request {
http_method_t method; // HTTP method (e.g., GET, POST)
char *path; // Request path
char *body; // Request body
int content_length; // Length of the body
struct map *headers; // HTTP headers
int websocket; // Is this a WebSocket request?
};
HTTP Response
struct http_response {
http_error_t status; // HTTP status code
struct map *headers; // Response headers
char *body; // Response body
};
WebSocket
struct websocket {
int client_fd; // Client file descriptor
int (*send)(struct websocket* ws, const char *message, size_t length);
int (*close)(struct websocket* ws);
};
Docker
Build and run the server using Docker:
docker build -t cweb .
docker run -p 8080:8080 --mount type=bind,source=$(pwd)/modules,target=/app/modules cweb
Or use Docker Compose:
docker-compose up --build
For non-volatile modules during restarts, you need to mount the modules directory:
volumes:
- ./modules:/app/modules
FAQ
Frequently asked questions about c-web-modules.
Q: How do I restart the server?
A: Use `make run` after making changes.
Q: How do I debug a failing module?
A: Check logs in the console or the HTTP response from /mgnt.