Layer: Foundation (tutorial) ยท Build flags: core (this example overrides defaults rather than enabling features)
What this example teaches
Everything in the library is sized at compile time, and this example is the reference for the knobs. It strips optional features down to a lean REST-only profile, tightens every capacity constant, exposes routes that echo the active configuration so you can confirm your overrides took effect, and demonstrates a runtime config struct. The sketch's header comment is itself a cheat-sheet of every flag and constant.
Overrides go BEFORE the include. Each #define must appear before #include "protocore.h" so the library compiles with your value instead of the default. Here the optional subsystems are stripped and the buffers are shrunk for a small sensor node:
#define PROTOCORE_ENABLE_WEBSOCKET 0
#define PROTOCORE_ENABLE_SSE 0
#define PROTOCORE_ENABLE_MULTIPART 0
#define PROTOCORE_ENABLE_FILE_SERVING 0
#define PROTOCORE_ENABLE_AUTH 0
#define MAX_CONNS 2
#define RX_BUF_SIZE 512
#define BODY_BUF_SIZE 128
#include "protocore.h"
When compiling with pio ci (separate library translation units), these in-sketch #defines only affect the sketch. Pass them as build_flags so the library compiles with them too - see the build-flag tree and the repository's contributing notes.
Capacity constants are visible at runtime. GET /config serializes the active sizing constants as JSON, so you can verify a build without a debugger:
snprintf(body, sizeof(body), "{\"MAX_CONNS\":%u,\"RX_BUF_SIZE\":%u,\"BODY_BUF_SIZE\":%u,...}",
#define RX_BUF_SIZE
Ring-buffer capacity in bytes per connection slot (feature floors enforced last, in derived_sizing....
#define BODY_BUF_SIZE
Maximum request body bytes stored in HttpReq::body.
#define MAX_CONNS
Maximum simultaneous TCP connections (fixed static pool; ~3.95 KB of internal RAM per slot).
The limits are real. With BODY_BUF_SIZE=128, a POST body over 128 bytes is rejected with an automatic 413 before your handler runs. With MAX_QUERY_PARAMS=4, a fifth query parameter is parsed but silently dropped - GET /search echoes exactly what was kept so you can see the boundary.
Runtime config struct. A WebServerConfig passed to begin() overrides the idle timeout without a rebuild (pass nullptr to use the built-in default, CONN_TIMEOUT_MS):
int32_t result = server.begin(80, &cfg);
#define CONN_TIMEOUT_MS
Compile-time default for connection idle timeout in milliseconds.
The header comment also documents the feature-dependency tree (a child flag needs its parent; illegal combinations fail with a compile-time #error).
Build and run
pio ci --board=esp32dev --project-option="framework=arduino" \
--project-option="build_flags=-DPROTOCORE_ENABLE_DIAG=1" \
--lib="." examples/Foundation/Configuration/Configuration.ino
curl http://<ip>/config # see the active sizing constants
curl -X POST http://<ip>/echo -d "hello" # bodies > BODY_BUF_SIZE get a 413
curl "http://<ip>/search?q=esp32&sort=date" # extra params past MAX_QUERY_PARAMS are dropped
Annotated source
The complete sketch (Configuration.ino). The long header comment (a full flag/constant reference) is kept verbatim; the C++ is annotated.
#define PROTOCORE_ENABLE_WEBSOCKET 0
#define PROTOCORE_ENABLE_SSE 0
#define PROTOCORE_ENABLE_MULTIPART 0
#define PROTOCORE_ENABLE_FILE_SERVING 0
#define PROTOCORE_ENABLE_AUTH 0
#define PROTOCORE_ENABLE_DIAG 1
#define MAX_CONNS 2
#define EVT_QUEUE_DEPTH 8
#define RX_BUF_SIZE 512
#define BODY_BUF_SIZE 128
#define MAX_ROUTES 8
#define MAX_HEADERS 6
#define MAX_PATH_LEN 48
#define MAX_KEY_LEN 16
#define MAX_VAL_LEN 32
#define MAX_QUERY_LEN 64
#define MAX_QUERY_PARAMS 4
#define QUERY_KEY_LEN 16
#define QUERY_VAL_LEN 24
#define CONN_TIMEOUT_MS 3000
#include "protocore.h"
static const char *SSID = "YOUR_SSID";
static const char *PASSWORD = "YOUR_PASSWORD";
PC server;
void handle_config(uint8_t slot_id,
HttpReq *req)
{
char body[384];
snprintf(body, sizeof(body),
"{"
"\"MAX_CONNS\":%u,"
"\"RX_BUF_SIZE\":%u,"
"\"CONN_TIMEOUT_MS\":%u,"
"\"MAX_HEADERS\":%u,"
"\"MAX_PATH_LEN\":%u,"
"\"MAX_KEY_LEN\":%u,"
"\"MAX_VAL_LEN\":%u,"
"\"MAX_QUERY_LEN\":%u,"
"\"MAX_QUERY_PARAMS\":%u,"
"\"QUERY_KEY_LEN\":%u,"
"\"QUERY_VAL_LEN\":%u,"
"\"BODY_BUF_SIZE\":%u,"
"\"MAX_ROUTES\":%u"
"}",
server.send(slot_id, 200, "application/json", body);
}
void handle_echo(uint8_t slot_id,
HttpReq *req)
{
server.send(slot_id, 200,
"text/plain", (
const char *)req->
body);
}
void handle_search(uint8_t slot_id,
HttpReq *req)
{
char body[256] = "params: ";
{
if (i > 0)
strncat(body, ", ", sizeof(body) - strlen(body) - 1);
strncat(body, "=", sizeof(body) - strlen(body) - 1);
}
server.send(slot_id, 200, "text/plain", body);
}
void setup()
{
Serial.begin(115200);
Serial.println("\n--- Active PC config ---");
Serial.printf(
" MAX_CONNS = %u\n", (
unsigned)
MAX_CONNS);
Serial.printf(
" RX_BUF_SIZE = %u\n", (
unsigned)
RX_BUF_SIZE);
Serial.println("----------------------------------");
Physical.wifi->init(SSID, PASSWORD);
Serial.print("Connecting to WiFi");
while (!Physical.wifi->ready())
{
delay(250);
Serial.print('.');
}
uint32_t ip = Physical.link->egress_ip();
Serial.printf("IP: %u.%u.%u.%u\n", (unsigned)(ip & 0xFF), (unsigned)((ip >> 8) & 0xFF),
(unsigned)((ip >> 16) & 0xFF), (unsigned)((ip >> 24) & 0xFF));
int32_t result = server.begin(80, &cfg);
if (result < 0)
{
Serial.printf("begin() failed (error %d)\n", result);
return;
}
Serial.println("Server started on port 80");
}
void loop()
{
server.handle();
}
#define MAX_VAL_LEN
Maximum header field-value length.
#define MAX_QUERY_PARAMS
Maximum number of parsed query-string parameters.
#define MAX_QUERY_LEN
Maximum raw query-string length (everything after ?).
#define QUERY_VAL_LEN
Maximum query-parameter value length.
#define MAX_HEADERS
Maximum HTTP headers stored per request.
#define MAX_PATH_LEN
Maximum URL path length (including leading /).
#define QUERY_KEY_LEN
Maximum query-parameter key length.
#define MAX_KEY_LEN
Maximum header field-name length (e.g. "Content-Type").
#define MAX_ROUTES
Maximum simultaneously registered routes.
@ HTTP_GET
Safe, idempotent read.
@ HTTP_POST
Non-idempotent create / action.
Layer 1 (Physical) - link bring-up, the interface registry, and live egress reporting.
QueryParam query_params[MAX_QUERY_PARAMS]
uint8_t body[BODY_BUF_SIZE+1]