An HTTP/1.1 server written in C for Windows using the Winsock2 API. Handles multiple client connections concurrently, serves static files, and exposes a simple JSON route.
- Multi-threaded client handling via
_beginthreadex: socket passed directly per thread, no heap allocation per connection - IPv4 & IPv6 dual-stack support (
IPV6_V6ONLY = 0allows IPv4-mapped connections on an IPv6 socket) - Static file serving with MIME type detection (
.html,.css,.js,.json,.png,.jpg,.gif,.svg,.txt) - Built-in
/helloJSON route returning{"message":"Hello from Windows HTTP Server!"} - Directory listing with
Content-Lengthwhenindex.htmlis absent - Path traversal protection: requests escaping the docroot are rejected with 403
- Request logging to stdout:
[date] METHOD path -> status - Recv timeout (10 s) to prevent hung clients from holding threads indefinitely
- Query string stripping before filesystem resolution
- Fully offline, no external dependencies
GIT_HTTP_SERVER_WINDOWS/
├── GitProject.c # Server source code
├── GitProjectServer.exe # Compiled binary (after build)
├── index.html # Default page served at http://127.0.0.1:8080/
└── Makefile.win # Dev-C++ project makefile
Note: The server looks for index.html in whichever directory you pass to -r. If it is missing, the server will return a directory listing instead. To get started quickly, drop any index.html into the same folder as the executable and run:
./GitProjectServer.exe -p 8080 -r .Command line (MinGW):
gcc GitProject.c -o GitProjectServer.exe -lws2_32 -std=gnu11 -O2 -Wall -WextraThe
#pragma comment(lib, "Ws2_32.lib")warning from MinGW is harmless — Winsock is linked correctly via-lws2_32on the command line.
Dev-C++ 5.11:
Open the project file, press F11 or go to Execute → Compile & Run.
If you see Winsock linking errors, confirm your linker flags include -lws2_32.
Start the server:
./GitProjectServer.exe -p 8080 -r .Then open your browser:
http://127.0.0.1:8080/— servesindex.htmlfrom the specified directoryhttp://127.0.0.1:8080/hello— returns{"message":"Hello from Windows HTTP Server!"}http://127.0.0.1:8080/somedir/— directory listing if noindex.htmlpresent
Each incoming connection is dispatched to a new OS thread:
_beginthreadex(NULL, 0, client_thread, (void*)(uintptr_t)cs, 0, NULL);The main thread stays free to call accept continuously. A 10-second SO_RCVTIMEO timeout is applied to each socket before dispatch so that slow or silent clients cannot hold a thread open indefinitely.
Requests are checked for path traversal before any file is opened. The raw URL target is joined with the docroot, resolved to an absolute path via _fullpath, and then verified to still sit inside the docroot prefix. Requests that escape it — e.g. GET /../../sensitive.txt — receive a 403 Forbidden and are logged.
This server is intended for local and educational use only. It has no TLS, rate limiting, or authentication. Do not expose it to untrusted networks or deploy it in any production environment.
WSAStartup/WSACleanupmanage the Winsock lifecyclegetaddrinfowithAF_UNSPECandIPV6_V6ONLY = 0enables dual-stack on a single sockethttp_date()produces a GMT string in HTTP date format using aCRITICAL_SECTION+gmtimewrapper for thread safetylog_request()is also protected by aCRITICAL_SECTIONso concurrent threads don't interleave log outputwarnx()for non-fatal messages,die()for fatal errors (callsExitProcess(1))- Directory listing body is buffered in full before sending so
Content-Lengthis always accurate
MIT — free for personal and educational use.
Dimitrios Dalaklidis — CS student at the University of Western Macedonia, interested in backend development and systems programming. dalaklidesdemetres@gmail.com