1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
6 * @brief Thorough entry-level example demonstrating core DetWebServer features.
8 * This example showcases:
9 * 1. WiFi provisioning and polling connection status using wifi_ready().
10 * 2. Initializing DetWebServer with standard configurations.
11 * 3. Enabling cross-origin resource sharing (CORS) with set_cors().
12 * 4. Creating route handlers for specific HTTP methods:
13 * - GET / -> Serving basic text greetings.
14 * - GET /api/status -> Generating custom JSON payloads and reading query strings.
15 * - POST /api/echo -> Reading the incoming request body safely.
16 * - GET /files/* -> Using wildcard path patterns.
17 * 5. Registering a custom 404 handler for unmatched routes.
19 * To run this example:
20 * - Update SSID and PASSWORD with your network credentials.
21 * - Upload to an ESP32 board.
22 * - Monitor serial output at 115200 baud.
25#include "DeterministicESPAsyncWebServer.h"
26#include "network_drivers/physical.h"
29// WiFi Credentials - Replace with your network settings
30static const char *SSID = "YOUR_SSID";
31static const char *PASSWORD = "YOUR_PASSWORD";
33// Server instance on default HTTP port
36// Simple state to track requests since boot
37static unsigned long boot_requests = 0;
40 * @brief Handler for GET /
41 * Serves a simple plain text welcome message.
43void handle_root(uint8_t slot_id, HttpReq *req)
46 server.send(slot_id, 200, "text/plain", "Welcome to the Deterministic ESP Async Web Server!");
50 * @brief Handler for GET /api/status
51 * Reads optional query parameter "?detailed=1" and replies with a JSON status payload.
53void handle_status(uint8_t slot_id, HttpReq *req)
57 // Query parameter lookup is O(N) where N is number of parsed parameters (max 8)
58 const char *detailed_param = http_get_query(req, "detailed");
59 bool detailed = (detailed_param && strcmp(detailed_param, "1") == 0);
61 char response_buf[256];
64 snprintf(response_buf, sizeof(response_buf),
65 "{\"status\":\"online\",\"uptime_ms\":%lu,\"requests\":%lu,\"free_heap\":%u}", millis(), boot_requests,
70 snprintf(response_buf, sizeof(response_buf), "{\"status\":\"online\",\"requests\":%lu}", boot_requests);
73 server.send(slot_id, 200, "application/json", response_buf);
77 * @brief Handler for POST /api/echo
78 * Echoes the raw request body back to the client.
80void handle_echo(uint8_t slot_id, HttpReq *req)
84 // req->body is guaranteed to be null-terminated by the presentation layer parser.
85 // Length is capped by BODY_BUF_SIZE (default 256 bytes) to ensure zero dynamic allocations.
86 if (req->body_len == 0)
88 server.send(slot_id, 400, "text/plain", "Error: Request body is empty");
92 server.send(slot_id, 200, "text/plain", (const char *)req->body);
96 * @brief Handler for GET /files/*
97 * Matches any request prefixing /files/ and prints the wildcard sub-path.
99void handle_files(uint8_t slot_id, HttpReq *req)
103 // For /files/* route, req->path holds the full path (e.g. "/files/images/logo.png")
105 snprintf(message, sizeof(message), "Requested path details: %s", req->path);
106 server.send(slot_id, 200, "text/plain", message);
110 * @brief Custom Not Found (404) Fallback handler
111 * Triggered when no registered route matches the request path or method.
113void handle_not_found(uint8_t slot_id, HttpReq *req)
116 snprintf(error_msg, sizeof(error_msg), "Error 404: Resource '%s' with method '%s' not found.", req->path,
118 server.send(slot_id, 404, "text/plain", error_msg);
123 Serial.begin(115200);
125 Serial.println("\n--- DetWebServer Basic Example ---");
127 // Initialize WiFi using the physical network driver layer
128 init_wifi_physical(SSID, PASSWORD);
129 Serial.print("Connecting to SSID: ");
130 Serial.println(SSID);
132 // Poll until connection is established
133 while (!wifi_ready())
138 Serial.println("\nWiFi Connected!");
139 Serial.print("IP Address: ");
140 Serial.println(WiFi.localIP());
142 // Enable CORS from any origin for development ease
143 server.set_cors("*");
146 server.on("/", HTTP_GET, handle_root);
147 server.on("/api/status", HTTP_GET, handle_status);
148 server.on("/api/echo", HTTP_POST, handle_echo);
149 server.on("/files/*", HTTP_GET, handle_files);
151 // Register custom fallback handler
152 server.on_not_found(handle_not_found);
154 // Start server on port 80
155 if (server.begin(80))
157 Serial.println("Deterministic HTTP server started successfully on port 80");
161 Serial.println("Failed to start server. lwIP error occurred.");
167 // The core handle() function executes the parser state machines, performs session
168 // timeout sweeps (O(MAX_CONNS)), and dispatches requests. It must be called
169 // continuously without blocking delay() calls in loop().