Repository navigation
RaftWebServerSysMod
Built-in SysMod that hosts an HTTP server, exposes the REST API over HTTP, optionally serves static files, and registers WebSocket channels with the Comms Channels layer.
- HTTP server on a configurable port with a configurable REST API path prefix.
-
REST API bridge — every endpoint registered via
RestAPIEndpointManager::addEndpoint()is reachable asGET/POST/PUT/DELETE <prefix>/<endpoint>.... - Deferred responses — an endpoint may defer its reply. A GET endpoint is called from the responder's loop; a POST (or other method) endpoint once the whole request body has been received. The response (and its headers, which include the length) is sent when the endpoint completes it, and the connection isn't timed out as idle meanwhile (the deferral's own timeout, at most 60 s, and the 5-minute connection limit still apply). If the client disconnects first, the response is discarded.
-
File uploads off the main loop — a
fileuploadPOST's chunks are written on the file system worker, not in the web server's loop. The web server stops reading the request body while 16 KB waits to be written (TCP flow control then slows the client), and the reply is deferred until the file is written (see ProtocolExchange). - Static file serving from any mounted file system (LittleFS / SPIFFS / SD). Each chunk of a file is read on the file system worker, the next one read ahead while the current one is sent (or read in place if the worker can't take the job).
-
WebSocket channels — each entry in the
websocketsarray becomes one or more comms channels using a chosen protocol codec. -
webcertsREST endpoint for uploading TLS certificates.
Place a WebServer block in the SysType SysMods array. Typical values:
| Key | Default | Meaning |
|---|---|---|
enable |
false |
Master switch |
webServerPort |
80 |
TCP listen port |
apiPrefix |
"/api" |
Path prefix for REST endpoints — /api/subscription etc. |
fileServer |
true |
Enable static file handler |
numConnSlots |
12 |
Max concurrent HTTP connections |
stdRespHeaders |
[] |
Header lines added to every response |
staticFilePaths |
"/=/<defaultFS>,/files/local=/local,/files/sd=/sd" |
Comma-separated urlPath=fsPath pairs |
websockets |
[] |
Array of websocket configs (see below) |
taskCore, taskPriority, taskStack
|
0, 9, 5000
|
Web server task |
sendMax |
20000 |
Max unsent outbound data held per connection (bytes); a send that would exceed it fails the connection - see Memory use and WebSocket behaviour |
clearPendingMs |
0 |
If > 0, drop pending tx after this many ms |
Each connection can queue up to sendMax bytes of unsent data when the link drains slowly (e.g. weak WiFi). These buffers use PSRAM when the board has it and it is enabled (CONFIG_SPIRAM), and otherwise internal RAM, which WiFi and lwIP also need. With the defaults (12 slots × 20000 bytes) a board without PSRAM can run out of internal RAM under concurrent downloads.
On boards without PSRAM:
- Consider lowering
numConnSlotsandsendMax. - In RaftWebServer versions after 1.16.1, a send buffer that can't be grown, or a file chunk that can't be allocated, fails that connection instead of crashing.
- File downloads are read and sent in chunks of at most 4096 bytes (
RAFT_WEB_FILE_CHUNK_MAX_BYTES, which can be defined in the build to change it), rather than up tosendMax.
Each HTTP or WebSocket connection uses an lwIP socket and an active TCP connection, as do the listeners, mDNS, SNTP, NetBIOS, DNS and the application. The ESP-IDF defaults are too small for 12 connection slots, and when they run out new connections are reset by lwIP before the web server sees them. Recommended settings for the SysType's sdkconfig.defaults (or the project's systypes/Common/sdkconfig.defaults):
CONFIG_LWIP_MAX_SOCKETS=24
CONFIG_LWIP_TCP_ACCEPTMBOX_SIZE=16
CONFIG_LWIP_MAX_ACTIVE_TCP=32
In RaftWebServer versions after 1.16.1:
-
Startup warning: a warning is logged if
numConnSlotsplus the sockets other things typically need exceedsCONFIG_LWIP_MAX_SOCKETS. -
Busy response: a connection which can't be given a slot gets
503 Service UnavailablewithRetry-After: 1, rather than being closed (which the client sees as a reset). - Bursts: several waiting connections are accepted per main loop pass, so a burst of connections is handled.
With these settings a UM FeatherS3 served bursts of up to 24 simultaneous requests with no failures.
On boards with PSRAM, enable it in the SysType's sdkconfig.defaults (CONFIG_SPIRAM=y and the board's mode, e.g. CONFIG_SPIRAM_MODE_QUAD=y or CONFIG_SPIRAM_MODE_OCT=y). Note that in RaftCore 1.58.1 and earlier the PSRAM-aware buffers didn't use PSRAM under ESP-IDF 5 and later, even when it was enabled. This is fixed in later versions.
| Key | Default | Meaning |
|---|---|---|
pfix |
"ws" |
URL path prefix and channel interface name |
pcol |
"RICSerial" |
Protocol codec to attach (RICSerial, RICFrame, RICJSON) |
maxConn |
5 |
Max simultaneous websocket connections |
pktMaxBytes |
100000 |
Longest message received (longer ones are dropped) |
inboundBlockLen |
24000 with PSRAM (capped at pktMaxBytes), otherwise the channel default (1200) |
The comms channel's inboundBlockLen. RICREST file uploads use blocks of up to 2/3 of it, so up to 16000 bytes with PSRAM, 800 without |
pingMs |
30000 |
Ping interval (0 for none) |
closeIfNoPong |
false |
Close the connection if no pong arrives within 2 × pingMs + 2 s |
content |
"binary" |
binary or text messages |
txQueueMax |
20 |
Outbound queue depth - only used if WEBSOCKET_SEND_USE_TX_QUEUE is defined (it isn't by default) |
Each connection slot is registered with CommsChannelManager as a channel named <pfix>_<idx>, so connection 0 to pfix:"ws" becomes channel ws_0. See Comms Channels.
-
Receiving: fragmented messages (a first frame and continuation frames) are put back together, each fragment unmasked with its own mask key, and a ping or pong between fragments doesn't disturb them. A message longer than
pktMaxBytesis dropped (only its own frames are skipped), and so is one whose receive buffer can't be grown with an 8 KB margin left (SpiramAwareAllocator::max_allocatable()). A frame whose header gives a length overpktMaxBytescloses the link with status 1009 (message too big). Receive buffers use PSRAM where available and grow geometrically. -
Sending: each frame is written once - the header, then the data, appended to reserved space - with no zero-filled buffer. Sends happen on the main task (the channel callbacks must only be called from it). By default (
WEBSOCKET_SEND_USE_TX_QUEUEnot defined) a frame is sent at once; data the socket can't take now is held in the connection's send buffer (up tosendMax) and sent as the socket drains. -
Back-pressure: before a publish is sent on a WebSocket channel the web server checks the connection can send now (
canSendBufferOnChannel(): no unsent data held, and the socket writable), so high-rate publishers drop messages rather than overflow the send buffer and close the connection. Other messages only check that the channel is connected. See RaftCoredevdocs/websocket-backpressure-analysis.md.
| Endpoint | Method | Purpose |
|---|---|---|
webcerts/set |
POST | Upload TLS certificates (body = JSON document) |
Every other endpoint visible over HTTP comes from other SysMods registering with RestAPIEndpointManager. The web server simply forwards.
void serveStaticFiles(const char* servePaths, const char* cacheControl = nullptr);
void enableServerSideEvents(const String& eventsURL);
void sendServerSideEvent(const char* eventContent, const char* eventGroup);These are typically called from your application's setup() after RaftCoreApp::setup().
- Adding REST API Endpoints
- Communications Stack Overview
- Comms Channels
- Network Manager SysMod — required for an active network interface
Getting Started
- Quick Start
- Architecture at a Glance
- Writing Your First SysMod
- Adding a Comms Channel
- Adding an I2C Device Type
Scaffolding & Building
- Raft CLI
- Web Apps (Device Types, Flasher)
- SysTypes
- Top-Level SysType
- Build Process
- WebUI Build Pipeline
- File System
- Partitions & Flash
- Local Dev Libraries
- Library Developer Guide
Architecture
Built-in SysMods
- NetworkManager
- WiFi Troubleshooting
- BLEManager
- WebServer
- MQTTManager
- SerialConsole
- CommandSerial
- CommandSocket
- CommandFile
- FileManager
- LogManager
- ESPOTAUpdate
- StatePublisher
- Remote Logging
- Data Source Registration
Comms & Protocols
- Stack Overview
- Comms Channels
- ProtocolExchange
- RICREST Protocol
- Real-Time Streams
- Adding REST Endpoints
- Built-in REST Endpoints
- File Download (OKTO)
- OTA Update Flow
Devices & Buses
- DeviceManager
- Device Manager REST API
- Device Factory & Classes
- Device Type Records
- Adding an I2C Device Type
- Device Data Publishing
- Data Logger
- I2C Bus
- I2C Device Scanning
- I2C ID & Polling
- MotorControl Overview
- MotorControl Config
- MotorControl Commands
- Camera
ROS 2
Helpers
Reference
{ "name": "WebServer", "enable": 1, "webServerPort": 80, "apiPrefix": "api/", "fileServer": 1, "numConnSlots": 6, "stdRespHeaders": [ "Access-Control-Allow-Origin: *" ], "staticFilePaths": "/=/local,/files/sd=/sd", "websockets": [ { "pfix": "ws", "pcol": "RICSerial", "maxConn": 4, "txQueueMax": 20, "pingMs": 30000 } ], "taskCore": 0, "taskPriority": 5, "taskStack": 5000, "sendMax": 5000, "clearPendingMs": 0 }