networking · intermediate · ~25 min

Parse HTTP request line (method + path)

Robust delimited parsing with bounds-checked copies.

Challenge

Split an HTTP request line into its method and path — the first parse every web server does, and a classic spot for buffer bugs.

Task

Implement int http_parse_request_line(const char *line, char *method, size_t mlen, char *path, size_t plen).

An HTTP request line looks like METHOD PATH HTTP/1.x (often ending in \r\n), e.g. GET /index.html HTTP/1.1\r\n. Copy the method into method and the path into path, each NUL-terminated.

Input

  • line: the request-line string.
  • method, mlen: output buffer for the method and its capacity.
  • path, plen: output buffer for the path and its capacity.

Output

Return 1 on success (method and path copied). Return 0 on malformed input: no first space, no second space, an empty method or path, missing HTTP/, or a method/path that does not fit its buffer.

Example

"GET /index.html HTTP/1.1\r\n"     ->  1, method="GET",  path="/index.html"
"POST /api/v1/x?y=1 HTTP/1.0\r\n"  ->  1, method="POST", path="/api/v1/x?y=1"
"garbage"                          ->  0   (no spaces)
"GET /a"                           ->  0   (no HTTP/ part)

Edge cases

  • A path may contain a query string (?foo=bar) — copy it verbatim.
  • A method or path that doesn't fit its buffer (including the NUL) returns 0; don't overflow.

Why this matters

The HTTP request line is where a web server first decides what to do. Every nginx, every Node http module, every Go http.Server starts with this exact parse — and historical RCE bugs (Apache Range, nginx alias) hide here.

Input format

line, the request-line string; method/mlen and path/plen, output buffers and their sizes.

Output format

1 on success with method and path filled (NUL-terminated); 0 on malformed input or buffers too small.

Constraints

Reject if method or path (plus NUL) doesn't fit its buffer; require a 'HTTP/' token after the path.

Starter code

#include <stddef.h>
int http_parse_request_line(const char *line, char *method, size_t mlen, char *path, size_t plen) { /* TODO */ return 0; }

Common mistakes

Reading past \r\n; accepting lowercase methods (per RFC, methods are case-sensitive — uppercase by convention); buffer overrun by trusting the path length.

Edge cases to handle

Path with query string ?foo=bar. Method OPTIONS. Missing path.

Complexity

O(line length).

Background lessons

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