Skip to content

Serving static files

wired_staticfile_resolve turns a request path into a file under a document root, rejecting path traversal, and wired_mimetype_for_path picks the Content-Type from its extension. This page serves two files committed next to the snippet and answers 404 for anything else.

Code

main.c
#define WIRED_MAIN
#include "wired.h"
/* The whole point of this page: wired_staticfile_resolve rejects path
* traversal and picks an index file for a directory request, then
* wired_mimetype_for_path infers the Content-Type from the resolved
* file's extension. */
/* Serve one round of the resolved file's bytes at x->offset, 404 if it
* does not resolve or open/read. */
static int on_request(void* ctx, wired_http_exchange* x) {
char resolved[256], reqpath[128];
ssz fd, total, got;
(void)ctx;
wired_span_to_cstr(reqpath, sizeof reqpath, wired_h3req_path(x->req));
if (!wired_staticfile_resolve(
".", reqpath, "index.html", resolved, sizeof resolved))
return wired_http_reply_text(x, 404, "not found");
fd = wired_fio_open(resolved);
if (fd < 0) return wired_http_reply_text(x, 404, "not found");
total = wired_fio_size(resolved);
got =
wired_fio_pread(fd, wired_mspan_of(x->body->p, x->body->cap), x->offset);
wired_fio_close(fd);
if (total < 0 || got < 0) return wired_http_reply_text(x, 404, "not found");
if (x->offset == 0) {
x->content_type = wired_mimetype_for_path(resolved);
x->total_size = (u64)total;
}
x->body->len = (usz)got;
if (x->offset + (u64)got < (u64)total) x->more = 1;
return 1;
}
int wired_main(int argc, char** argv) {
/* Fixed demo identity (self-signed certificate; never for production). */
static wired_srvboot_demo_keys keys;
wired_srvboot_id id;
wired_srvboot_demo(&id, &keys, 0x50, "guide-h3");
u16 port = (u16)wired_cliargs_int(argc, argv, "--port", 4433);
wired_srvrun_handler h = {.http = on_request};
wired_srvrun_obs obs = {0};
return wired_server_run(port, &id, h, obs) ? 0 : 1;
}

Output

Terminal window
$ ./h3-static-files --port 4433
conn closed by peer (CONNECTION_CLOSE)
Terminal window
$ probe h3get 127.0.0.1:4433 /hello.txt /page.html /nope.txt
GET /hello.txt status=200 content-type=text/plain body="hello static file"
GET /page.html status=200 content-type=text/html body="<h1>hi</h1>"
GET /nope.txt status=404 content-type=text/plain body="not found"
  • wired_staticfile_resolve(".", reqpath, "index.html", resolved, cap) resolves the request path under the current directory, rejecting any .. segment.
  • wired_mimetype_for_path(resolved) reads the resolved path’s extension (.txt → text/plain, .html → text/html), set once on the first round, like wired_h3reqdrive’s own content-type field.
  • wired_fio_open / wired_fio_size / wired_fio_pread / wired_fio_close stream the file in chunks of x->body->cap, the same chunked read the word_list example uses for a document root larger than one round.
  • A missing file, or one wired_staticfile_resolve rejects, answers a real 404 via x->status (wired_http_handler, like the fix on the routing page).