This repository documents a lightweight HTTP server stack for ESP32/Arduino built on top of esp_http_server. The goal is to ship a coherent set of behaviors—dynamic handlers, template & head injections, filesystem/in-memory static serving with gzip, and consistent error hooks—so that sketches can follow the same rules. The full specification lives in SPEC.md.
- Response Stack –
send()/sendText()/sendStatic()/sendFile()plus chunked helpers, redirects, and asendError()path that feeds a globalErrorRenderer. - Templates & Head Injection – Streamed HTML renderer handles
{{key}}(escaped) /{{{key}}}(raw). Head injection drops CSP/script/meta snippets right after<head>so you can toggle analytics or policy tags without editing every file. Both features automatically disable themselves for gzipped payloads, so precompressed assets stay untouched. - Static Lifecycle –
serveStatic()resolves filesystem or memory assets, prefers.gzsiblings, auto-detectsindex.html|htm, and even auto-sends (or 404s) if a handler forgets to respond. - Routing & Fallbacks –
on()supports literal/param/wildcard scoring,onNotFound()acts as a catch-all, and unhandled requests automatically return 500/404 instead of stalling. - Logging Discipline – All response logs share the
[RESP][tag] <code> ...format and respect the board’s Core Debug Level so you can dial verbosity from “silent” to “deep internals”.
void send(int code, const char* type,
const uint8_t* data, size_t len);
void sendText(int code, const char* type,
const String& text);
void beginChunked(int code, const char* type);
void sendChunk(const char* text);
void sendStatic();
void sendFile(fs::FS& fs, const String& fsPath);
void sendError(int status);
void redirect(const char* location, int status = 302);- HTML responses (including
send()/sendText()) pass through the streaming template + head injection pipeline whenContent-Typeistext/htmland the payload is not gzipped. sendStatic()/sendFile()stream data directly from FS or memory chunks; gzipped assets automatically setContent-Encoding: gzipand skip templating.sendError()sets the status, logs[RESP][ERR] <code>, and either invokes the globalErrorRendereror emits a built-in short message (e.g., “Not Found”).Response::setErrorRenderer()lets sketches render custom HTML/JSON error pages without rewriting every handler.
serveStatic("/www", LittleFS, "/wwwroot", handler)normalizes the URI, joins it withbasePath, prefers.gz, detects directories, and probesindex.htmlthenindex.htm.- The memory variant accepts parallel arrays (
paths,data,sizes) and mirrors the same gzip + directory probing logic. - Handlers still get the final say (e.g., SPA fallback). But if they forget to call
sendStatic()/sendFile()/sendError()/redirect(), the library auto-falls back:StaticInfo.exists == true→ callsendStatic()automatically.- Otherwise → emit
sendError(404).
server.on("/user/:id", HTTP_GET, handler)parses segments into literal/parameter/wildcard buckets. Routes are scored (literal +3,param +2,wildcard +1) and registration order breaks ties.- If no dynamic route matches,
onNotFound()runs. Leaving that handler without a response triggers an automatic 404. - If a dynamic handler (or
onNotFound()) returns without sending, the library callssendError(500)(or 404 for the catch-all) so connections never hang.
[RESP]logs are uniform:send()logs[RESP] 200 text/html 512 bytes,sendStatic()logs[RESP][STATIC][FS] 200 /index.html (plain) origin=/wwwroot/index.html, errors use[RESP][ERR] 404.- Choose Core Debug Level (None/Error/Info/Debug) in the Arduino IDE or via
arduino-clibuild flags.Nonesuppresses every log—evenESP_LOGE.
- BasicDynamic – Hello-world dynamic response.
- ChunkedStream – Emits JSON via chunked transfer.
- TemplateHead – Demonstrates
setTemplateHandler+ head injection. - StaticFS – Serves
/datauploaded to LittleFS/SPIFFS. - EmbeddedAssetsSimple – Shows how bundled headers generated by the VS Code extension feed
serveStatic. - PathParams – Uses
req.pathParam()for literal/param/wildcard routes. - ErrorHandling – Registers
Response::setErrorRenderer()andonNotFound()to deliver branded error pages.
- The Arduino CLI Wrapper VS Code extension uploads
data/folders to FS targets and converts asset directories into header bundles (assets_www_embed.h) with optional gzip/minify. - Re-run the generator whenever assets change so the embedded headers stay in sync.