A lightweight, educational web server built using only the C standard library that demonstrates:
- HTTP request parsing and routing
- RESTful JSON APIs
- Middleware pattern
- Route handlers
- Query parameter parsing
- Method-based routing (GET, POST, PUT, DELETE)
- Pattern matching for dynamic routes (e.g.,
/api/users/:id) - Exact path matching
- Automatic 404 handling
- Logger: Logs all incoming requests with timestamps
- Authentication: Protects routes (e.g.,
/admin) - CORS: Placeholder for cross-origin support
- Middleware chain execution (order matters!)
- RESTful endpoints with JSON responses
- Proper Content-Type headers
- HTTP status codes (200, 201, 404, 401, etc.)
- Request body parsing
GET /- HTML home page with route listing
GET /api/hello?name=YourName- Personalized greetingGET /api/time- Current server timeGET /api/users- List all usersPOST /api/users- Create a new userGET /api/users/123- Get specific user by IDDELETE /api/users/123- Delete user by ID
GET /admin- Requires Authorization header
makeOr manually:
gcc -Wall -Wextra -std=c11 -o webserver webserver.cmake runOr:
./webserverThe server will start on http://localhost:8080
make cleanBasic GET request:
curl http://localhost:8080/JSON API request:
curl http://localhost:8080/api/hello?name=AliceGet current time:
curl http://localhost:8080/api/timeList users:
curl http://localhost:8080/api/usersGet specific user:
curl http://localhost:8080/api/users/1Create user (POST):
curl -X POST http://localhost:8080/api/users \
-H "Content-Type: application/json" \
-d '{"name":"John","email":"john@example.com"}'Delete user:
curl -X DELETE http://localhost:8080/api/users/1Access protected route (will fail):
curl http://localhost:8080/admin
# Returns: {"error": "Unauthorized"}Access with auth (simplified demo):
curl http://localhost:8080/admin -H "Authorization: Bearer token"
# Returns: {"message": "Welcome to admin panel"}Simply open: http://localhost:8080
You'll see an HTML page listing all available endpoints.
1. Client Connection
↓
2. Parse HTTP Request → HttpRequest struct
↓
3. Execute Middleware Chain
↓
4. Route Matching
↓
5. Execute Handler → HttpResponse struct
↓
6. Send HTTP Response
↓
7. Close Connection
typedef struct {
HttpMethod method; // GET, POST, PUT, DELETE
char path[256]; // Request path
char query_string[512]; // Query parameters
char body[2048]; // Request body
int body_length; // Body size
char headers[1024]; // Raw headers
} HttpRequest;typedef struct {
int status_code; // 200, 404, etc.
char content_type[64]; // "application/json", etc.
char body[4096]; // Response body
int body_length; // Body size
} HttpResponse;typedef bool (*Middleware)(HttpRequest*, HttpResponse*);
// Returns true to continue, false to stop processingtypedef void (*RouteHandler)(HttpRequest*, HttpResponse*);webserver.c
├── Utility Functions
│ ├── parse_method()
│ ├── parse_request()
│ ├── set_json_response()
│ └── set_html_response()
│
├── Middleware Functions
│ ├── logger_middleware()
│ ├── cors_middleware()
│ └── auth_middleware()
│
├── Route Handlers
│ ├── handle_home()
│ ├── handle_hello()
│ ├── handle_users_list()
│ ├── handle_user_create()
│ └── handle_not_found()
│
├── Routing System
│ ├── register_route()
│ ├── register_middleware()
│ ├── find_handler()
│ └── handle_request()
│
└── Main Server Loop
├── setup_routes()
├── socket creation
├── bind and listen
└── accept and handle connections
// 1. Create a handler function
void handle_my_route(HttpRequest* req, HttpResponse* res) {
set_json_response(res, 200, "{\"message\": \"Hello!\"}");
}
// 2. Register in setup_routes()
void setup_routes() {
// ... existing routes ...
register_route(GET, "/my-route", handle_my_route);
}// 1. Create middleware function
bool my_middleware(HttpRequest* req, HttpResponse* res) {
// Do something before the handler
printf("Custom middleware executing\n");
return true; // Continue to next middleware/handler
}
// 2. Register in setup_routes()
void setup_routes() {
register_middleware(my_middleware);
// ... other registrations ...
}void handle_search(HttpRequest* req, HttpResponse* res) {
char query[128] = "default";
if (req->query_string[0]) {
char* q = strstr(req->query_string, "q=");
if (q) {
sscanf(q, "q=%127s", query);
}
}
char json[256];
snprintf(json, sizeof(json),
"{\"query\": \"%s\", \"results\": []}", query);
set_json_response(res, 200, json);
}void handle_json_body(HttpRequest* req, HttpResponse* res) {
// Simple JSON parsing (use a library for production)
char name[64] = "";
char* name_field = strstr(req->body, "\"name\":");
if (name_field) {
sscanf(name_field, "\"name\":\"%63[^\"]\"", name);
}
printf("Parsed name: %s\n", name);
set_json_response(res, 200, "{\"received\": true}");
}This is an educational server. For production use, consider:
- ❌ Not thread-safe (single-threaded)
- ❌ No HTTPS/TLS support
- ❌ Limited buffer sizes
- ❌ No proper JSON parsing library
- ❌ No persistent data storage
- ❌ Basic error handling
- ❌ No request timeout handling
- ❌ No compression support
This server demonstrates:
- ✅ Socket programming in C
- ✅ HTTP protocol fundamentals
- ✅ Routing and middleware patterns
- ✅ RESTful API design
- ✅ Function pointers and callbacks
- ✅ String parsing in C
- ✅ Struct-based architecture
- GCC compiler with C11 support
- POSIX-compliant system (Linux, macOS, WSL)
- Standard C library
- POSIX sockets
MIT License - Feel free to use for learning and educational purposes.