Skip to content

Latest commit

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

HTTP in C

A minimal HTTP/1.1 static file server in a single C file. It accepts TCP connections, parses GET request lines, maps URL paths to the filesystem, and streams file contents back with correct headers. A live access log prints every request with status code, byte count, and response time. Concurrent requests are handled via fork().

Part of the Corg-Labs collection of single-file C programs.


Features

  • TCP socket lifecycle: socketbindlistenaccept
  • GET and HEAD method support; 405 for everything else
  • %xx URL decoding and directory-traversal (..) protection
  • Automatic index.html serving for directory paths
  • MIME type table covering HTML, CSS, JS, JSON, PNG, JPEG, SVG, WASM, and more
  • fork()-per-connection concurrency; zombie reaping via SIGCHLD

Tutorial

1. TCP Socket Setup

intlfd=socket(AF_INET, SOCK_STREAM, 0);
intyes=1;
setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
structsockaddr_inaddr= {
.sin_family=AF_INET,
.sin_port=htons((uint16_t)port),
.sin_addr.s_addr=INADDR_ANY,
};
bind(lfd, (structsockaddr*)&addr, sizeof(addr));
listen(lfd, 64);

SO_REUSEADDR lets the port be rebound immediately after restart.

2. Fork-per-Connection Concurrency

pid_tpid=fork();
if (pid==0) {
close(lfd); /* child doesn't need listener */handle_client(cfd, root);
close(cfd);
exit(0);
}
close(cfd); /* parent closes its copy */

SIGCHLD is caught by a handler that calls waitpid(-1, NULL, WNOHANG) to reap zombies.

3. HTTP Request Parsing

charmethod[16], raw_path[1024], proto[16];
sscanf(req, "%15s %1023s %15s", method, raw_path, proto);

URL percent-encoding is decoded: %xx hex sequences are converted to their byte values. Any path containing .. is rejected with 403.

4. MIME Type Resolution

staticconstmime_entry_tMIME_TABLE[] = {
{ "html", "text/html; charset=utf-8" },
{ "js", "application/javascript" },
{ "png", "image/png" },
{ NULL, "application/octet-stream" }, /* fallback */
};

strrchr finds the file extension; the table is scanned with strcasecmp.

5. File Streaming

snprintf(hdr, sizeof(hdr),
"HTTP/1.1 200 OK\r\nContent-Type: %s\r\n""Content-Length: %lld\r\nConnection: close\r\n\r\n",
mime, (long long)st.st_size);
send_all(cfd, hdr, hlen);
charbuf[8192];
while ((n=read(ffd, buf, sizeof(buf))) >0)
send_all(cfd, buf, n);

send_all loops until every byte is written, handling short writes.


Build

gcc http.c -o http

Run

./http # port 8080, serve current directory
./http 9090 /var/www # custom port and root

Open http://localhost:8080/ in a browser. The terminal shows a live access log.


Concepts Practiced

  • TCP socket lifecycle (socket, bind, listen, accept)
  • HTTP/1.1 request and response format
  • fork()-per-connection concurrency and zombie reaping
  • URL percent-decoding and path sanitisation
  • MIME type resolution from file extensions
  • Reliable write loops for streaming file content

Dependencies

Standard C library + POSIX (sys/socket.h, sys/stat.h, sys/wait.h). No external libraries.

About

▶ A minimal HTTP/1.1 static file server in a single C file

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages