DeterministicESPAsyncWebServer 1.2.0
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
basic.ino
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file basic.ino
6 * @brief Thorough entry-level example demonstrating core DetWebServer features.
7 *
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.
18 *
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.
23 */
24
25#include "DeterministicESPAsyncWebServer.h"
26#include "network_drivers/physical.h"
27#include <WiFi.h>
28
29// WiFi Credentials - Replace with your network settings
30static const char *SSID = "YOUR_SSID";
31static const char *PASSWORD = "YOUR_PASSWORD";
32
33// Server instance on default HTTP port
34DetWebServer server;
35
36// Simple state to track requests since boot
37static unsigned long boot_requests = 0;
38
39/**
40 * @brief Handler for GET /
41 * Serves a simple plain text welcome message.
42 */
43void handle_root(uint8_t slot_id, HttpReq *req)
44{
45 boot_requests++;
46 server.send(slot_id, 200, "text/plain", "Welcome to the Deterministic ESP Async Web Server!");
47}
48
49/**
50 * @brief Handler for GET /api/status
51 * Reads optional query parameter "?detailed=1" and replies with a JSON status payload.
52 */
53void handle_status(uint8_t slot_id, HttpReq *req)
54{
55 boot_requests++;
56
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);
60
61 char response_buf[256];
62 if (detailed)
63 {
64 snprintf(response_buf, sizeof(response_buf),
65 "{\"status\":\"online\",\"uptime_ms\":%lu,\"requests\":%lu,\"free_heap\":%u}", millis(), boot_requests,
66 ESP.getFreeHeap());
67 }
68 else
69 {
70 snprintf(response_buf, sizeof(response_buf), "{\"status\":\"online\",\"requests\":%lu}", boot_requests);
71 }
72
73 server.send(slot_id, 200, "application/json", response_buf);
74}
75
76/**
77 * @brief Handler for POST /api/echo
78 * Echoes the raw request body back to the client.
79 */
80void handle_echo(uint8_t slot_id, HttpReq *req)
81{
82 boot_requests++;
83
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)
87 {
88 server.send(slot_id, 400, "text/plain", "Error: Request body is empty");
89 return;
90 }
91
92 server.send(slot_id, 200, "text/plain", (const char *)req->body);
93}
94
95/**
96 * @brief Handler for GET /files/*
97 * Matches any request prefixing /files/ and prints the wildcard sub-path.
98 */
99void handle_files(uint8_t slot_id, HttpReq *req)
100{
101 boot_requests++;
102
103 // For /files/* route, req->path holds the full path (e.g. "/files/images/logo.png")
104 char message[128];
105 snprintf(message, sizeof(message), "Requested path details: %s", req->path);
106 server.send(slot_id, 200, "text/plain", message);
107}
108
109/**
110 * @brief Custom Not Found (404) Fallback handler
111 * Triggered when no registered route matches the request path or method.
112 */
113void handle_not_found(uint8_t slot_id, HttpReq *req)
114{
115 char error_msg[128];
116 snprintf(error_msg, sizeof(error_msg), "Error 404: Resource '%s' with method '%s' not found.", req->path,
117 req->method);
118 server.send(slot_id, 404, "text/plain", error_msg);
119}
120
121void setup()
122{
123 Serial.begin(115200);
124 delay(1000);
125 Serial.println("\n--- DetWebServer Basic Example ---");
126
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);
131
132 // Poll until connection is established
133 while (!wifi_ready())
134 {
135 delay(500);
136 Serial.print(".");
137 }
138 Serial.println("\nWiFi Connected!");
139 Serial.print("IP Address: ");
140 Serial.println(WiFi.localIP());
141
142 // Enable CORS from any origin for development ease
143 server.set_cors("*");
144
145 // Register routes
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);
150
151 // Register custom fallback handler
152 server.on_not_found(handle_not_found);
153
154 // Start server on port 80
155 if (server.begin(80))
156 {
157 Serial.println("Deterministic HTTP server started successfully on port 80");
158 }
159 else
160 {
161 Serial.println("Failed to start server. lwIP error occurred.");
162 }
163}
164
165void loop()
166{
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().
170 server.handle();
171}