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:

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:

For Arch Linux:

For MacOS:

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.