networking · intermediate · ~12 min · safe pentest lab

Hand-build a minimal HTTP/1.0 GET request

Build a valid HTTP/1.0 request as a string — and enforce the localhost-only safety boundary at the byte level.

Challenge

Build the exact bytes of a minimal HTTP/1.0 GET request as a string. No sockets — this is pure string-building.

Task

Implement int build_http_get(const char *host, const char *path, char *out, int cap) that writes a minimal HTTP/1.0 GET request into out (NUL-terminated), including the trailing blank line.

Input

  • host: must be the string "127.0.0.1" exactly.
  • path: the request path; must start with /.
  • out: caller-provided buffer to write into.
  • cap: capacity of out in bytes.

Output

The request has this exact form:

GET <path> HTTP/1.0\r\nHost: <host>\r\n\r\n

Return the number of bytes written (excluding the trailing NUL), or -1 on any validation failure or if the result would not fit in cap.

Example

build_http_get("127.0.0.1", "/", buf, 256)            ->  35, buf = "GET / HTTP/1.0\r\nHost: 127.0.0.1\r\n\r\n"
build_http_get("127.0.0.1", "/index.html", buf, 256)  ->  buf starts "GET /index.html HTTP/1.0\r\n..."
build_http_get("example.com", "/", buf, 256)          ->  -1   (host not 127.0.0.1)
build_http_get("127.0.0.1", "index.html", buf, 256)   ->  -1   (path has no leading /)
build_http_get("127.0.0.1", "/", buf, 8)              ->  -1   (won't fit)

Edge cases

  • A path with a ?query is fine — only the leading / is checked.
  • A cap too small to hold the full request (plus NUL) returns -1, never a truncated request.
  • NULL host, path, or out, or cap <= 0, return -1.

Rules

  • host must equal "127.0.0.1" exactly — any other value returns -1 (defensive boundary).
  • Do not touch the network.

Why this matters

HTTP is just bytes. Building them by hand once removes the mystery and makes every web-related lesson click.

Input format

host (must be "127.0.0.1"), path (must start with /), out buffer, and cap (its size).

Output format

Bytes written excluding the NUL on success; -1 on any validation failure or if the request would not fit.

Constraints

host and path are null-terminated strings; out has capacity cap bytes.

Starter code

#include <stdio.h>
#include <string.h>
int build_http_get(const char *host, const char *path, char *out, int cap) {
    /* TODO */
    return -1;
}

Common mistakes

Using single '\n' instead of '\r\n' CRLF pairs or ignoring snprintf overflow.

Edge cases to handle

Truncated output when cap is small, path without leading slash.

Background lessons

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.