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 must be 127.0.0.1 exactly; path must start with /; never overflow out; pure string-building, no sockets.

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

Missing the trailing blank line. Hardcoding localhost instead of host. Not rejecting a too-small cap.

Edge cases to handle

Query string in path is fine (only leading / checked). cap = 0 must return -1. NULL inputs reject.

Background lessons

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