Skip to content

labib0x9/ccybe

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

57 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ccybe

A minimal HTTP server written in C, focused on learning low-level networking, event loops, multithreading, file serving and server architecture.


Overview

ccybe provides a thin abstraction over POSIX sockets and HTTP parsing to help you build a basic HTTP/1.1 server without hiding core system concepts. It is not a production-ready framework; it is a learning-oriented project. Also it uses kqueue for event loop, which is only available in FreeBSD based OS (MacOS).


Features

  • TCP server abstraction (socket, bind, listen, accept)
  • Basic HTTP/1.1 request parsing (via llhttp)
  • Simple routing system (hash table based)
  • Event-loop–based client handling with a thread-pool–based request parser and response generator
  • Static file serving

Getting started

Prerequisites

  • macOS or FreeBSD (kqueue is not available on Linux)
  • GCC
  • Node.js (required to build llhttp from source)
  • GNU Make

1. Clone with submodules

git clone --recurse-submodules https://github.com/labib0x9/ccybe.git
cd ccybe

If you already cloned without --recurse-submodules:

git submodule update --init --recursive

2. Build llhttp

llhttp generates its C source from a TypeScript definition, so Node.js is required once at build time:

cd third_party/llhttp     # adjust path to wherever your submodule lives
npm install
make
cd ../..

klib is header-only — no build step needed.

3. Build and run

make run

The server starts on :8080 by default. To serve static files, place them under ./www/ directory.


Usage

1. Create a TCP Listener

Create a TCP server bound to all interfaces on port 8080. Internally, s_listen() wraps socket(), bind(), and listen().

listener_t ln = s_listen("tcp", ":8080");
if (ln.err != 0) {
    // handle error
}

2. Accept Client Connections

Accept incoming connections and abstract the file descriptor and address into a client_t.

while (1) {
    client_t conn = s_accept(ln);
    // handle conn
}

3. Basic TCP Server Example

#include "cnet.h"

void handle_conn(client_t client) {
    // handle client
    conn_close(client);
}

int main(void) {
    listener_t ln = s_listen("tcp", ":8080");
    if (ln.err != 0) {
        perror("listener failed");
        return 1;
    }

    while (1) {
        client_t conn = s_accept(ln);
        handle_conn(conn);
    }

    s_close(ln);
    return 0;
}

4. HTTP Parser Usage

Parse an HTTP/1.1 request using the built-in request context abstraction.

#include "parser.h"

static const char CLOSE_CONN[] =
    "HTTP/1.1 200 OK\r\n"
    "Content-Length: 6\r\n"
    "Connection: close\r\n"
    "\r\n"
    "CLOSED";

int main(void) {
    request_ctx_t ctx;
    init_ctx(&ctx);

    int ok = parse_http_request(&ctx, CLOSE_CONN, strlen(CLOSE_CONN));
    if (ok == 1) {
        // bad request
    } else {
        // process request
    }

    printf("Path = %s\n", ctx.req.path);

    reset_ctx(&ctx);
    return 0;
}

5. Basic HTTP Server Example

#include "http.h"

void default_page(response_ctx_t* wctx, request_ctx_t* rctx) {
    // handle root path
}

void api_front_page(response_ctx_t* wctx, request_ctx_t* rctx) {
    // handle /api
}

int main(void) {
    server_t server;
    init_server(&server);

    // default timeouts are 10 sec for both
    // set custom timeout
    server.recv_timeout = 60;
    server.send_timeout = 60;

    register_route(&server, "/", default_page);
    register_route(&server, "/api", api_front_page);

    serve_and_listen(&server, ":8080");
    return 0;
}

Useful APIs

int serve_and_listen(server_t* server, const char *address);
void init_server(server_t* server);
void register_route(server_t* server, const char* path, route_handler_fn func);
typedef void (*route_handler_fn)(response_ctx_t*, request_ctx_t*);

void set_header(response_ctx_t* ctx, const char* header, const char* value);

Dependencies

  • llhttp (git submodule) — HTTP request parsing
  • klib (git submodule) — hash table implementation

Current State

  • Multiple client handling via an event loop and thread pool
  • HTTP/1.1 request parsing (no chunked transfer encoding)
  • Basic GET method support
  • Multiple header values are not fully supported
  • Basic Connection: keep-alive handling, not really. Connection are closed after the response.
  • Routing via hash table lookup
  • Static file serving, but connection is closed so same issue, no clean path (path traversal vuln).
  • Graceful shutdown is incomplete.

Roadmap

Planned improvements for a more complete HTTP/1.1 server:

  • Static file serving (default path is ./www/), if index.html is not present then directory listing.
  • Structured logging
  • Robust error handling
  • Proper connection timeouts
  • Proper signal handling and graceful termination

Disclaimer

This project is intended for educational purposes. Expect breaking changes, rough edges, and incomplete features.

About

A minimal HTTP server written in C, focused on learning low-level networking, event loops, multithreading, file serving and server architecture.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors