Skip to content
/ Cserver Public

Minimal, small HTTP server written in C using the Win32/Winsock2 API. It serves static files from a directory and provides a tiny thread pool, access logging (Combined Log Format), and size-based log rotation.

License

Notifications You must be signed in to change notification settings

OMouta/Cserver

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Win32 C HTTP server (MSYS2 / MinGW)

Minimal, small HTTP server written in C using the Win32/Winsock2 API. It serves static files from a directory and provides a tiny thread pool, access logging (Combined Log Format), and size-based log rotation.

This repository is intended for learning, experimentation, and small internal use-cases. It is not a drop-in production web server.

Highlights

  • Serve a directory of static files (default public).
  • Small thread pool (configurable worker count).
  • Access logs written in Combined Log Format (CLF) when --log-file is used.
  • Size-based log rotation with --log-rotate-size and --log-rotate-count.
  • Graceful shutdown on Ctrl+C.
  • Minimal CGI support for dynamic content (PHP, Python, Perl, Ruby) via per-request processes.
  • PHP works with the php-cgi wrapper; supply a custom path with --php-cgi.

Build

You can build this project with MinGW (MSYS2) or using CMake. A CMakePresets.json is included with a mingw preset.

Recommended (CMake + MinGW):

PowerShell / cmd (uses the MinGW Makefiles generator):

cmake --preset mingw      # configure (uses CMakePresets.json)
cmake --build --preset release

Or the equivalent manual steps:

cmake -S . -B build -G "MinGW Makefiles"
cmake --build build --config Release

You can also use the provided helper scripts in scripts/:

.\scripts\build.ps1   # PowerShell helper (configures once and builds)

If you prefer to compile directly with gcc (MSYS2), the project can still be built with a single gcc command, but using CMake is recommended for consistent artifacts.

Run

When built with CMake the executable is produced under build/Release and is named Cserver.exe (or Cserver on non-Windows generators). The scripts/ helpers start the built binary and provide presets.

Default (serve ../public on port 8080 from repo root using the CMake build output):

.\build\Cserver.exe

Recommended (use the start helpers):

PowerShell:

.\scripts\start.ps1 -WithPhp -WithLogs

cmd.exe:

scripts\start.bat /php /logs

Examples (directly invoking the CMake-built executable):

  • Serve public on port 8080 with 4 workers and write access logs to server.log:
.\build\Cserver.exe --port 8080 --serve public --workers 4 --log-file .\server.log
  • Log rotation: rotate logs at ~10 MB and keep 5 rotated files:
.\build\Cserver.exe --log-file .\server.log --log-rotate-size 10M --log-rotate-count 5

Command-line flags

  • --port <port> — TCP port to listen on (default 8080).
  • --serve <path> — directory to serve (default public). --public is accepted as an alias for compatibility.
  • --workers <N> — number of worker threads in the pool (default 8).
  • --log-file <path> — append access and internal logs to the provided file.
  • --log-rotate-size <size> — enable size-based rotation; examples: 1K, 10M, 1G.
  • --log-rotate-count <n> — how many rotated files to keep (default 5).
  • --php-cgi <path> — optional: path to a php-cgi executable (or other CGI wrapper) to execute .php files; default is php-cgi (must be in PATH or an absolute path). When set, .php files under the served directory will be executed via CGI.

The server writes access logs in Combined Log Format when --log-file is set:

%h %l %u [%t] "%r" %>s %b "%{Referer}i" "%{User-agent}i"

Example access line:

127.0.0.1 - - [17/Aug/2025:00:35:10 +0000] "GET /index.html HTTP/1.1" 200 1024 "-" "curl/7.68.0"

Limitations and security notes

This server is intentionally small and educational. Recent hardening above (header, URI, and canonicalization limits) improves resilience, but there are still notable limitations:

  • No TLS. Use a reverse proxy (nginx, Caddy) or a TLS-terminating load balancer for production.
  • Minimal HTTP parsing: only basic GET is implemented; many headers and edge-cases are not fully RFC-compliant.
  • No rate limiting or per-IP connection limits.
  • Log rotation is simple rename-based; no compression or time-based rotation.
  • No authentication or authorization.
  • CGI is implemented by spawning an interpreter process per-request (CreateProcess). This is simple but not high-performance; for production-scale PHP use a FastCGI backend (php-fpm) and a FastCGI client/proxy in front of it.

If you need production-grade behavior, run this behind a hardened proxy or gateway and add tests + CI.

Files

  • src/server.c - server entrypoint and argument parsing
  • src/http.c / src/http.h - HTTP request parsing and static file serving (contains header/URI limits & canonicalization)
  • src/log.c / src/log.h - centralized logging and rotation
  • src/threadpool.c / src/threadpool.h - worker queue and thread pool
  • src/state.c / src/state.h - shared runtime state (running flag, listen socket)
  • src/utils.c / src/utils.h - small helpers (parse_size, header sanitization)
  • src/cgi.c / src/cgi.h - CGI request handling
  • Makefile - build helper
  • README.md - this file

Scripts

This repository includes simple helper scripts under the scripts/ directory to make building and starting the server easier on Windows (MinGW/gcc or cmd/PowerShell).

  • scripts/build.ps1 — PowerShell helper: configures (once) with the MinGW Makefiles generator and builds the Release target.
  • scripts/build.bat — cmd helper with the same behavior.
  • CMakePresets.json — contains a mingw configure preset and a release build preset. You can use cmake --preset mingw to configure and cmake --build --preset release to build.
  • scripts/start.ps1 — PowerShell start script with presets: -WithPhp, -WithLogs, -Port, -ServeDir, -PhpCgiPath, -LogFile.
  • scripts/start.bat — cmd start script. Flags: /php to enable --php-cgi, /logs to enable --log-file.

Examples

PowerShell (build + start with PHP and logs)

# configure/build
.\scripts\build.ps1

# start with php and logging
.\scripts\start.ps1 -WithPhp -WithLogs

cmd.exe (build + start)

scripts\build.bat
scripts\start.bat /php /logs

The default start command used by the scripts is equivalent to:

.\build\Cserver.exe --serve "public" --port 8080 --php-cgi "D:\IDE's\php-8.4.11-Win32-vs17-x64\php-cgi.exe" --log-file "server.log"

You can override the PHP path, port, and log file via the script parameters.

Contributing

Small patches, tests, and documentation improvements welcome. If you change public behavior (status codes, limits), please add tests that demonstrate the behavior.

License

This project uses the MIT License.

About

Minimal, small HTTP server written in C using the Win32/Winsock2 API. It serves static files from a directory and provides a tiny thread pool, access logging (Combined Log Format), and size-based log rotation.

Resources

License

Stars

Watchers

Forks