Skip to content

codcreater1/cpphttp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

⚑ cpphttp

A lightweight, dependency-free HTTP/1.1 server built in modern C++17 β€” from raw POSIX sockets up.

CI C++17 License: MIT Platform

                                      ___
  ___ _ __  _ __  | |__  | |_  |_|_|_ |_)
 / __| '_ \| '_ \ | '_ \ | __| | |  | |
| (__| |_) | |_) || | | || |_  | |  | |
 \___| .__/| .__/ |_| |_| \__| |_|  |_|
     |_|   |_|

cpphttp is a learning project that demonstrates how a real HTTP server works β€” no Boost, no libuv, no framework magic. Just sockets, threads, and clean modern C++.


✨ Features

Feature Details
HTTP/1.1 parser Method, path, query string, headers, body
Express-style routing GET /users/:id with named parameters
Middleware chain app.use(handler) β€” runs before every route
Static file serving Serve a directory with MIME detection
Thread pool One thread per connection (configurable)
Colourised logger Access log + structured log levels
Zero dependencies Only the C++17 standard library + POSIX

πŸ“Έ Screenshots

Server running β€” 12 threads, live access log: terminal

Browser output at localhost:8080: browser


πŸš€ Quick Start

Prerequisites

  • CMake β‰₯ 3.16
  • GCC β‰₯ 9 or Clang β‰₯ 10 (with C++17 support)
  • Linux or macOS

Build

git clone https://github.com/codcreater1/cpphttp.git
cd cpphttp
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallel

Run the Hello World example

./build/hello_world
# cpphttp listening on http://0.0.0.0:8080 [8 threads]

Open http://localhost:8080 in your browser or:

curl http://localhost:8080/api/hello?name=Ada
# {"message":"Hello, Ada!","server":"cpphttp"}

curl http://localhost:8080/api/users/42
# {"user_id":"42","name":"Alice","role":"admin"}

πŸ“– API Reference

Creating a server

#include <cpphttp.hpp>
using namespace cpphttp;

Server app;                    // uses hardware_concurrency() threads
Server app(4);                 // explicit thread count

Routing

app.get("/",        handler);
app.post("/items",  handler);
app.put("/items/:id", handler);
app.del("/items/:id", handler);

Handler signature

[](const Request& req, Response& res) {
    // Access path params
    std::string id = req.param("id").value_or("0");

    // Access query params  β†’ /search?q=hello
    std::string q  = req.query_param("q").value_or("");

    // Access headers
    std::string ct = req.header("content-type").value_or("");

    // Send responses
    res.json(R"({"ok":true})");
    res.html("<h1>Hello</h1>");
    res.status(201).send("Created");
    res.status(404).json(R"({"error":"not found"})");
}

Middleware

// Simple request logger
app.use([](const Request& req, Response& /*res*/) {
    std::cout << req.method << " " << req.path << "\n";
});

// Auth guard (short-circuit by calling res.send())
app.use([](const Request& req, Response& res) {
    if (req.header("x-api-key") != "secret") {
        res.status(401).json(R"({"error":"Unauthorized"})");
    }
});

Static files

app.serve_static("/public", "./www");
// GET /public/index.html β†’ serves ./www/index.html

Start & stop

app.listen(8080);                   // blocks; default host 0.0.0.0
app.listen(3000, "127.0.0.1");      // custom host

// Graceful shutdown (e.g. from signal handler)
app.stop();

πŸ—‚ Project Structure

cpphttp/
β”œβ”€β”€ include/
β”‚   β”œβ”€β”€ cpphttp.hpp          ← Single include
β”‚   └── cpphttp/
β”‚       β”œβ”€β”€ server.hpp       ← Core server
β”‚       β”œβ”€β”€ request.hpp      ← HTTP request model
β”‚       β”œβ”€β”€ response.hpp     ← HTTP response builder
β”‚       β”œβ”€β”€ router.hpp       ← Path-param router
β”‚       └── logger.hpp       ← Colourised logger
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ server.cpp
β”‚   β”œβ”€β”€ request.cpp
β”‚   β”œβ”€β”€ response.cpp
β”‚   β”œβ”€β”€ router.cpp
β”‚   └── logger.cpp
β”œβ”€β”€ examples/
β”‚   β”œβ”€β”€ hello_world.cpp      ← Getting started
β”‚   └── todo_api.cpp         ← Full CRUD REST API
β”œβ”€β”€ .github/
β”‚   └── workflows/ci.yml     ← GitHub Actions CI
└── CMakeLists.txt

πŸ” How It Works

This is the interesting bit β€” here's the lifecycle of a request:

Client
  β”‚
  β”‚  TCP connect
  β–Ό
accept()          ← main thread blocks here
  β”‚
  β”‚  spawn std::thread
  β–Ό
recv()            ← read raw bytes from socket
  β”‚
Request::parse()  ← tokenise HTTP/1.1 request line + headers
  β”‚
Middleware chain  ← app.use() handlers run in order
  β”‚
Router::match()   ← regex match path, extract :params
  β”‚
Route handler     ← your lambda runs here
  β”‚
Response::to_raw() ← serialise status + headers + body
  β”‚
send()            ← write to socket
  β”‚
close()

πŸ§ͺ Running the Todo API example

./build/todo_api

# Create
curl -X POST http://localhost:8080/todos \
     -H 'Content-Type: application/json' \
     -d '{"title":"Learn C++ sockets"}'

# List
curl http://localhost:8080/todos

# Update
curl -X PUT http://localhost:8080/todos/1 \
     -H 'Content-Type: application/json' \
     -d '{"done":true}'

# Delete
curl -X DELETE http://localhost:8080/todos/1

πŸ›£ Roadmap

  • keep-alive connection reuse
  • Chunked transfer encoding
  • HTTP/2 (h2c) upgrade
  • TLS via OpenSSL (opt-in)
  • multipart/form-data parser
  • WebSocket upgrade
  • Route groups / sub-routers

🀝 Contributing

Pull requests are welcome! Please:

  1. Fork the repo and create a feature branch
  2. Keep changes focused and well-commented
  3. Ensure the CI build passes
  4. Open a PR with a clear description

πŸ“„ License

MIT Β© 2024 β€” see LICENSE for details.

About

No description or website provided.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors