DeterministicESPAsyncWebServer
1.2.0
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
DetWebServerConfig.h
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 DetWebServerConfig.h
6
* @brief User-facing configuration for DeterministicESPAsyncWebServer.
7
*
8
* **Compile-time sizing constants**
9
* These govern static array dimensions and must be set before the first
10
* library header is included. Define any of them in your sketch or in a
11
* build flag before including this file to override the defaults:
12
* @code
13
* // platformio.ini
14
* build_flags = -DMAX_CONNS=8 -DBODY_BUF_SIZE=512
15
* @endcode
16
*
17
* **Runtime parameters — flash or RAM, your choice**
18
* `WebServerConfig` holds values that can be changed without a rebuild.
19
* On ESP32, `PROGMEM` is a no-op (const data lands in DROM automatically).
20
* On AVR it places data in flash and requires `pgm_read_*` accessors — this
21
* library targets ESP32 only, so both forms read identically via pointer:
22
* @code
23
* // Flash (PROGMEM, no RAM cost at runtime):
24
* const WebServerConfig my_cfg PROGMEM = { .conn_timeout_ms = 10000 };
25
*
26
* // RAM (can be changed at runtime):
27
* WebServerConfig my_cfg = { .conn_timeout_ms = 10000 };
28
*
29
* server.begin(80, &my_cfg);
30
* @endcode
31
* Pass `nullptr` (or omit the argument) to use `DET_DEFAULT_CONFIG`.
32
*/
33
34
#ifndef DETERMINISTICESPASYNCWEBSERVER_CONFIG_H
35
#define DETERMINISTICESPASYNCWEBSERVER_CONFIG_H
36
37
#include <stdint.h>
38
39
// ---------------------------------------------------------------------------
40
// Compile-time capacity constants (affect static array sizes)
41
// ---------------------------------------------------------------------------
42
43
/** @brief Maximum simultaneous TCP connections. */
44
#ifndef MAX_CONNS
45
#define MAX_CONNS 4
46
#endif
47
48
/** @brief Ring-buffer capacity in bytes per connection slot. */
49
#ifndef RX_BUF_SIZE
50
#define RX_BUF_SIZE 1024
51
#endif
52
53
/**
54
* @brief Compile-time default for connection idle timeout in milliseconds.
55
*
56
* The actual runtime value is stored in `WebServerConfig::conn_timeout_ms`
57
* and loaded into `DeterministicAsyncTCP::conn_timeout_ms` by init().
58
*/
59
#ifndef CONN_TIMEOUT_MS
60
#define CONN_TIMEOUT_MS 5000
61
#endif
62
63
/** @brief Maximum HTTP headers stored per request. */
64
#ifndef MAX_HEADERS
65
#define MAX_HEADERS 8
66
#endif
67
68
/** @brief Maximum URL path length (including leading `/`). */
69
#ifndef MAX_PATH_LEN
70
#define MAX_PATH_LEN 64
71
#endif
72
73
/** @brief Maximum header field-name length (e.g. `"Content-Type"`). */
74
#ifndef MAX_KEY_LEN
75
#define MAX_KEY_LEN 24
76
#endif
77
78
/** @brief Maximum header field-value length. */
79
#ifndef MAX_VAL_LEN
80
#define MAX_VAL_LEN 48
81
#endif
82
83
/** @brief Maximum raw query-string length (everything after `?`). */
84
#ifndef MAX_QUERY_LEN
85
#define MAX_QUERY_LEN 128
86
#endif
87
88
/** @brief Maximum number of parsed query-string parameters. */
89
#ifndef MAX_QUERY_PARAMS
90
#define MAX_QUERY_PARAMS 8
91
#endif
92
93
/** @brief Maximum query-parameter key length. */
94
#ifndef QUERY_KEY_LEN
95
#define QUERY_KEY_LEN 24
96
#endif
97
98
/** @brief Maximum query-parameter value length. */
99
#ifndef QUERY_VAL_LEN
100
#define QUERY_VAL_LEN 48
101
#endif
102
103
/**
104
* @brief Maximum request body bytes stored in `HttpReq::body`.
105
*
106
* Bodies larger than this trigger a 413 Payload Too Large response —
107
* the parser detects the overflow via `Content-Length` before any body
108
* bytes arrive, so no data is read or stored for oversized requests.
109
*/
110
#ifndef BODY_BUF_SIZE
111
#define BODY_BUF_SIZE 256
112
#endif
113
114
/** @brief Maximum simultaneously registered routes. */
115
#ifndef MAX_ROUTES
116
#define MAX_ROUTES 16
117
#endif
118
119
// ---------------------------------------------------------------------------
120
// WebSocket sizing constants
121
// ---------------------------------------------------------------------------
122
123
/**
124
* @brief Maximum simultaneous WebSocket connections.
125
*
126
* Each connection occupies one TCP slot from MAX_CONNS and one entry in
127
* ws_pool[]. MAX_WS_CONNS + MAX_SSE_CONNS must not exceed MAX_CONNS.
128
*/
129
#ifndef MAX_WS_CONNS
130
#define MAX_WS_CONNS 2
131
#endif
132
133
/**
134
* @brief Maximum WebSocket frame payload in bytes.
135
*
136
* Frames larger than this are rejected with Close code 1009 (Message Too Big).
137
* Fragmented messages are not supported; each message must fit in one frame.
138
*/
139
#ifndef WS_FRAME_SIZE
140
#define WS_FRAME_SIZE 512
141
#endif
142
143
// ---------------------------------------------------------------------------
144
// Server-Sent Events sizing constants
145
// ---------------------------------------------------------------------------
146
147
/**
148
* @brief Maximum simultaneous SSE connections.
149
*
150
* Each connection occupies one TCP slot from MAX_CONNS and one entry in
151
* sse_pool[]. MAX_WS_CONNS + MAX_SSE_CONNS must not exceed MAX_CONNS.
152
*/
153
#ifndef MAX_SSE_CONNS
154
#define MAX_SSE_CONNS 2
155
#endif
156
157
/**
158
* @brief Output buffer size in bytes for a single SSE event.
159
*
160
* An event larger than this is silently truncated. The buffer holds the
161
* formatted `data: ...\n\n` line before it is handed to tcp_write().
162
*/
163
#ifndef SSE_BUF_SIZE
164
#define SSE_BUF_SIZE 256
165
#endif
166
167
// ---------------------------------------------------------------------------
168
// Static file serving sizing constants
169
// ---------------------------------------------------------------------------
170
171
/**
172
* @brief Bytes read from the filesystem and passed to tcp_write() per loop().
173
*
174
* Smaller values reduce peak stack use; larger values improve throughput.
175
* Must be <= RX_BUF_SIZE to avoid stalling the TCP send window.
176
*/
177
#ifndef FILE_CHUNK_SIZE
178
#define FILE_CHUNK_SIZE 512
179
#endif
180
181
// ---------------------------------------------------------------------------
182
// Basic Auth sizing constants
183
// ---------------------------------------------------------------------------
184
185
/**
186
* @brief Maximum username or password length for HTTP Basic Authentication.
187
*
188
* Both username and password must fit in this many bytes including the
189
* null terminator. Longer credentials are silently rejected with 401.
190
*/
191
#ifndef MAX_AUTH_LEN
192
#define MAX_AUTH_LEN 32
193
#endif
194
195
// ---------------------------------------------------------------------------
196
// Multipart form-data sizing constants
197
// ---------------------------------------------------------------------------
198
199
/**
200
* @brief Maximum simultaneously parsed multipart parts per request.
201
*
202
* Parts beyond this limit are silently ignored. A typical upload form
203
* has 1-4 fields; increase this for forms with more.
204
*/
205
#ifndef MAX_MULTIPART_PARTS
206
#define MAX_MULTIPART_PARTS 4
207
#endif
208
209
/**
210
* @brief Maximum MIME boundary length (RFC 2046 allows up to 70 characters).
211
*/
212
#ifndef MAX_BOUNDARY_LEN
213
#define MAX_BOUNDARY_LEN 72
214
#endif
215
216
// ---------------------------------------------------------------------------
217
// Event queue depth
218
// ---------------------------------------------------------------------------
219
220
/**
221
* @brief Depth of the FreeRTOS event queue shared between lwIP callbacks and
222
* the main-loop task.
223
*
224
* Each slot holds one TcpEvt (8 bytes). The queue is the only heap
225
* allocation the library makes at begin() time:
226
*
227
* heap = sizeof(StaticQueue_t) + EVT_QUEUE_DEPTH * sizeof(TcpEvt)
228
*
229
* Must be large enough to absorb a burst of MAX_CONNS * 4 events without
230
* blocking the lwIP thread. DeterministicAsyncTCP::heap_needed() returns
231
* the exact byte count; call DetWebServer::heap_available() before begin()
232
* to verify a contiguous block exists.
233
*/
234
#ifndef EVT_QUEUE_DEPTH
235
#define EVT_QUEUE_DEPTH 16
236
#endif
237
238
// ---------------------------------------------------------------------------
239
// Internal response buffer sizing constants
240
// ---------------------------------------------------------------------------
241
242
/**
243
* @brief Stack buffer for HTTP response header lines in send() / send_empty() /
244
* send_unauth() / serve_file().
245
*
246
* Must be large enough to hold the status line, Content-Type, Content-Length,
247
* Connection, and any CORS headers. The CORS block alone can reach
248
* CORS_HDR_BUF_SIZE bytes, so this value should be at least
249
* CORS_HDR_BUF_SIZE + 96.
250
*/
251
#ifndef RESP_HDR_BUF_SIZE
252
#define RESP_HDR_BUF_SIZE 512
253
#endif
254
255
/**
256
* @brief Stack buffer for the HTTP 101 Switching Protocols response sent during
257
* the WebSocket handshake.
258
*
259
* Must hold: status line + Upgrade + Connection + Sec-WebSocket-Accept (28
260
* base64 chars) + CRLF pairs. Minimum is ~120 bytes; default leaves margin.
261
*/
262
#ifndef WS_HDR_BUF_SIZE
263
#define WS_HDR_BUF_SIZE 256
264
#endif
265
266
/**
267
* @brief Size of the pre-built CORS header block stored in DetWebServer.
268
*
269
* Built once by set_cors() and injected into every response. Must hold
270
* Access-Control-Allow-Origin, Access-Control-Allow-Methods, and
271
* Access-Control-Allow-Headers lines for the configured origin.
272
*/
273
#ifndef CORS_HDR_BUF_SIZE
274
#define CORS_HDR_BUF_SIZE 192
275
#endif
276
277
// ---------------------------------------------------------------------------
278
// Feature flags
279
// ---------------------------------------------------------------------------
280
// Set any of these to 0 in your sketch BEFORE including this library to strip
281
// the feature from the build entirely (no code, no RAM, no flash cost).
282
//
283
// #define DETWS_ENABLE_WEBSOCKET 0
284
// #include <DeterministicESPAsyncWebServer.h>
285
286
/** @brief WebSocket support (RFC 6455 framing + SHA-1/base64 handshake). */
287
#ifndef DETWS_ENABLE_WEBSOCKET
288
#define DETWS_ENABLE_WEBSOCKET 1
289
#endif
290
291
/** @brief Server-Sent Events push support. */
292
#ifndef DETWS_ENABLE_SSE
293
#define DETWS_ENABLE_SSE 1
294
#endif
295
296
/** @brief multipart/form-data body parser. */
297
#ifndef DETWS_ENABLE_MULTIPART
298
#define DETWS_ENABLE_MULTIPART 1
299
#endif
300
301
/** @brief Static file serving via Arduino FS (LittleFS, SPIFFS, SD). */
302
#ifndef DETWS_ENABLE_FILE_SERVING
303
#define DETWS_ENABLE_FILE_SERVING 1
304
#endif
305
306
/** @brief HTTP Basic Authentication per-route. */
307
#ifndef DETWS_ENABLE_AUTH
308
#define DETWS_ENABLE_AUTH 1
309
#endif
310
311
/**
312
* @brief Expose a diagnostic JSON endpoint via server.diag().
313
*
314
* Disabled by default — enabling it exposes compile-time configuration
315
* (buffer sizes, feature flags) which could aid an attacker. Only
316
* enable in development or behind an authenticated route.
317
*
318
* When enabled, DETWS_DIAG_JSON is a compile-time string constant you can
319
* serve from any route handler:
320
* @code
321
* server.on("/diag", HTTP_GET, [](uint8_t id, HttpReq *) {
322
* server.diag(id); // convenience wrapper
323
* // or:
324
* server.send(id, 200, "application/json", DETWS_DIAG_JSON);
325
* });
326
* @endcode
327
*/
328
#ifndef DETWS_ENABLE_DIAG
329
#define DETWS_ENABLE_DIAG 0
330
#endif
331
332
// ---------------------------------------------------------------------------
333
// Runtime configuration struct
334
// ---------------------------------------------------------------------------
335
336
/**
337
* @brief Runtime-tunable server parameters.
338
*
339
* Can be declared as `const PROGMEM` (flash) or as a mutable variable (RAM).
340
* Pass a pointer to DetWebServer::begin() or DeterministicAsyncTCP::init().
341
*/
342
struct
WebServerConfig
343
{
344
/** Milliseconds of inactivity before a connection is force-closed. */
345
uint32_t
conn_timeout_ms
;
346
};
347
348
/** @brief Built-in defaults used when no config is supplied to begin(). */
349
static
const
WebServerConfig
DET_DEFAULT_CONFIG = {5000u};
350
351
// ---------------------------------------------------------------------------
352
// Diagnostic JSON string (only defined when DETWS_ENABLE_DIAG == 1)
353
// ---------------------------------------------------------------------------
354
// DETWS_DIAG_JSON is a compile-time string literal — zero runtime cost.
355
// Adjacent string literals are concatenated by the compiler; DETWS_STR()
356
// stringifies an integer macro value without evaluating it twice.
357
358
#if DETWS_ENABLE_DIAG
359
360
#define _DETWS_STR_(x) #x
361
#define _DETWS_STR(x) _DETWS_STR_(x)
362
363
#if DETWS_ENABLE_WEBSOCKET
364
#define _DETWS_F_WS "true"
365
#else
366
#define _DETWS_F_WS "false"
367
#endif
368
369
#if DETWS_ENABLE_SSE
370
#define _DETWS_F_SSE "true"
371
#else
372
#define _DETWS_F_SSE "false"
373
#endif
374
375
#if DETWS_ENABLE_MULTIPART
376
#define _DETWS_F_MP "true"
377
#else
378
#define _DETWS_F_MP "false"
379
#endif
380
381
#if DETWS_ENABLE_FILE_SERVING
382
#define _DETWS_F_FS "true"
383
#else
384
#define _DETWS_F_FS "false"
385
#endif
386
387
#if DETWS_ENABLE_AUTH
388
#define _DETWS_F_AUTH "true"
389
#else
390
#define _DETWS_F_AUTH "false"
391
#endif
392
393
#define DETWS_DIAG_JSON \
394
"{" \
395
"\"lib\":\"DeterministicESPAsyncWebServer\"," \
396
"\"features\":{" \
397
"\"websocket\":" _DETWS_F_WS "," \
398
"\"sse\":" _DETWS_F_SSE "," \
399
"\"multipart\":" _DETWS_F_MP "," \
400
"\"file_serving\":" _DETWS_F_FS "," \
401
"\"auth\":" _DETWS_F_AUTH \
402
"}," \
403
"\"config\":{" \
404
"\"MAX_CONNS\":" _DETWS_STR(MAX_CONNS) "," \
405
"\"RX_BUF_SIZE\":" _DETWS_STR(RX_BUF_SIZE) "," \
406
"\"BODY_BUF_SIZE\":" _DETWS_STR(BODY_BUF_SIZE) "," \
407
"\"MAX_ROUTES\":" _DETWS_STR(MAX_ROUTES) "," \
408
"\"MAX_HEADERS\":" _DETWS_STR(MAX_HEADERS) "," \
409
"\"MAX_PATH_LEN\":" _DETWS_STR(MAX_PATH_LEN) "," \
410
"\"MAX_KEY_LEN\":" _DETWS_STR(MAX_KEY_LEN) "," \
411
"\"MAX_VAL_LEN\":" _DETWS_STR(MAX_VAL_LEN) "," \
412
"\"MAX_QUERY_LEN\":" _DETWS_STR(MAX_QUERY_LEN) "," \
413
"\"MAX_QUERY_PARAMS\":" _DETWS_STR(MAX_QUERY_PARAMS) "," \
414
"\"CONN_TIMEOUT_MS\":" _DETWS_STR(CONN_TIMEOUT_MS) "," \
415
"\"RESP_HDR_BUF_SIZE\":" _DETWS_STR(RESP_HDR_BUF_SIZE) "," \
416
"\"WS_HDR_BUF_SIZE\":" _DETWS_STR(WS_HDR_BUF_SIZE) "," \
417
"\"CORS_HDR_BUF_SIZE\":" _DETWS_STR(CORS_HDR_BUF_SIZE) "," \
418
"\"EVT_QUEUE_DEPTH\":" _DETWS_STR(EVT_QUEUE_DEPTH) \
419
"}" \
420
"}"
421
422
#endif
// DETWS_ENABLE_DIAG
423
424
// ---------------------------------------------------------------------------
425
// Compile-time sanity checks
426
// ---------------------------------------------------------------------------
427
// These produce a clear #error message in the compiler output rather than a
428
// cryptic linker failure or silent misbehaviour.
429
430
#if EVT_QUEUE_DEPTH < MAX_CONNS * 4
431
#error "DeterministicESPAsyncWebServer: EVT_QUEUE_DEPTH must be >= MAX_CONNS * 4 to absorb event bursts without blocking lwIP"
432
#endif
433
434
#if MAX_CONNS < 1
435
#error "DeterministicESPAsyncWebServer: MAX_CONNS must be >= 1"
436
#endif
437
438
#if MAX_CONNS > 255
439
#error "DeterministicESPAsyncWebServer: MAX_CONNS must be <= 255 (slot IDs are uint8_t)"
440
#endif
441
442
#if DETWS_ENABLE_WEBSOCKET && DETWS_ENABLE_SSE
443
#if MAX_WS_CONNS + MAX_SSE_CONNS > MAX_CONNS
444
#error "DeterministicESPAsyncWebServer: MAX_WS_CONNS + MAX_SSE_CONNS must not exceed MAX_CONNS"
445
#endif
446
#elif DETWS_ENABLE_WEBSOCKET
447
#if MAX_WS_CONNS > MAX_CONNS
448
#error "DeterministicESPAsyncWebServer: MAX_WS_CONNS must not exceed MAX_CONNS"
449
#endif
450
#elif DETWS_ENABLE_SSE
451
#if MAX_SSE_CONNS > MAX_CONNS
452
#error "DeterministicESPAsyncWebServer: MAX_SSE_CONNS must not exceed MAX_CONNS"
453
#endif
454
#endif
455
456
#if BODY_BUF_SIZE < 1
457
#error "DeterministicESPAsyncWebServer: BODY_BUF_SIZE must be >= 1"
458
#endif
459
460
#if BODY_BUF_SIZE > RX_BUF_SIZE
461
#error "DeterministicESPAsyncWebServer: BODY_BUF_SIZE must not exceed RX_BUF_SIZE (parser reads from the ring buffer)"
462
#endif
463
464
#if DETWS_ENABLE_FILE_SERVING && FILE_CHUNK_SIZE > RX_BUF_SIZE
465
#error "DeterministicESPAsyncWebServer: FILE_CHUNK_SIZE must not exceed RX_BUF_SIZE"
466
#endif
467
468
#if MAX_KEY_LEN < 4
469
#error "DeterministicESPAsyncWebServer: MAX_KEY_LEN must be >= 4 (minimum valid HTTP header name length)"
470
#endif
471
472
#if MAX_VAL_LEN < 1
473
#error "DeterministicESPAsyncWebServer: MAX_VAL_LEN must be >= 1"
474
#endif
475
476
#if MAX_PATH_LEN < 2
477
#error "DeterministicESPAsyncWebServer: MAX_PATH_LEN must be >= 2 (minimum: \"/\")"
478
#endif
479
480
#if MAX_ROUTES < 1
481
#error "DeterministicESPAsyncWebServer: MAX_ROUTES must be >= 1"
482
#endif
483
484
#if DETWS_ENABLE_AUTH && MAX_AUTH_LEN < 2
485
#error "DeterministicESPAsyncWebServer: MAX_AUTH_LEN must be >= 2 when DETWS_ENABLE_AUTH is set"
486
#endif
487
488
#if DETWS_ENABLE_WEBSOCKET && WS_FRAME_SIZE < 2
489
#error "DeterministicESPAsyncWebServer: WS_FRAME_SIZE must be >= 2 when DETWS_ENABLE_WEBSOCKET is set"
490
#endif
491
492
#if DETWS_ENABLE_SSE && SSE_BUF_SIZE < 8
493
#error "DeterministicESPAsyncWebServer: SSE_BUF_SIZE must be >= 8 when DETWS_ENABLE_SSE is set"
494
#endif
495
496
#if DETWS_ENABLE_MULTIPART && MAX_MULTIPART_PARTS < 1
497
#error "DeterministicESPAsyncWebServer: MAX_MULTIPART_PARTS must be >= 1 when DETWS_ENABLE_MULTIPART is set"
498
#endif
499
500
#if RESP_HDR_BUF_SIZE < 128
501
#error "DeterministicESPAsyncWebServer: RESP_HDR_BUF_SIZE must be >= 128 (status line + headers + CORS block)"
502
#endif
503
504
#if DETWS_ENABLE_WEBSOCKET && WS_HDR_BUF_SIZE < 128
505
#error "DeterministicESPAsyncWebServer: WS_HDR_BUF_SIZE must be >= 128 when DETWS_ENABLE_WEBSOCKET is set"
506
#endif
507
508
#if CORS_HDR_BUF_SIZE < 64
509
#error "DeterministicESPAsyncWebServer: CORS_HDR_BUF_SIZE must be >= 64"
510
#endif
511
512
#if RESP_HDR_BUF_SIZE < CORS_HDR_BUF_SIZE
513
#error "DeterministicESPAsyncWebServer: RESP_HDR_BUF_SIZE must be >= CORS_HDR_BUF_SIZE (CORS block is injected into response headers)"
514
#endif
515
516
#endif
WebServerConfig
Runtime-tunable server parameters.
Definition
DetWebServerConfig.h:343
WebServerConfig::conn_timeout_ms
uint32_t conn_timeout_ms
Definition
DetWebServerConfig.h:345
src
DetWebServerConfig.h
Generated by
1.9.8