Skip to content

Commit 816e035

Browse files
committed
Split SimpleServer in multiple examples
1 parent 514d194 commit 816e035

File tree

31 files changed

+2013
-1409
lines changed

31 files changed

+2013
-1409
lines changed

.github/workflows/ci.yml

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,11 @@ jobs:
6868
if: ${{ matrix.core == 'rp2040:rp2040' }}
6969
run: ARDUINO_LIBRARY_ENABLE_UNSAFE_INSTALL=true arduino-cli lib install --git-url https://github.com/khoih-prog/AsyncTCP_RP2040W#v1.2.0
7070

71-
- name: Build CaptivePortal
72-
run: arduino-cli compile --library . --warnings none -b ${{ matrix.board }} "examples/CaptivePortal/CaptivePortal.ino"
73-
74-
- name: Build SimpleServer
75-
run: arduino-cli compile --library . --warnings none -b ${{ matrix.board }} "examples/SimpleServer/SimpleServer.ino"
76-
77-
- name: Build Filters
78-
run: arduino-cli compile --library . --warnings none -b ${{ matrix.board }} "examples/Filters/Filters.ino"
79-
80-
- name: Build StreamFiles
81-
run: arduino-cli compile --library . --warnings none -b ${{ matrix.board }} "examples/StreamFiles/StreamFiles.ino"
71+
- run: |
72+
for i in `ls examples`; do
73+
echo "Building examples/$i..."
74+
arduino-cli compile --library . --warnings none -b ${{ matrix.board }} "examples/$i/$i.ino"
75+
done
8276
8377
platformio:
8478
name: "pio:${{ matrix.env }}:${{ matrix.board }}"
@@ -147,7 +141,8 @@ jobs:
147141
python -m pip install --upgrade pip
148142
pip install --upgrade platformio
149143
150-
- run: PLATFORMIO_SRC_DIR=examples/CaptivePortal PIO_BOARD=${{ matrix.board }} pio run -e ${{ matrix.env }}
151-
- run: PLATFORMIO_SRC_DIR=examples/SimpleServer PIO_BOARD=${{ matrix.board }} pio run -e ${{ matrix.env }}
152-
- run: PLATFORMIO_SRC_DIR=examples/Filters PIO_BOARD=${{ matrix.board }} pio run -e ${{ matrix.env }}
153-
- run: PLATFORMIO_SRC_DIR=examples/StreamFiles PIO_BOARD=${{ matrix.board }} pio run -e ${{ matrix.env }}
144+
- run: |
145+
for i in `ls examples`; do
146+
echo "Building examples/$i..."
147+
PLATFORMIO_SRC_DIR=examples/$i PIO_BOARD=${{ matrix.board }} pio run -e ${{ matrix.env }}
148+
done

examples/Auth/Auth.ino

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
// SPDX-License-Identifier: LGPL-3.0-or-later
2+
// Copyright 2016-2025 Hristo Gochkov, Mathieu Carbou, Emil Muratov
3+
4+
//
5+
// Authentication and authorization middlewares
6+
//
7+
8+
#include <Arduino.h>
9+
#ifdef ESP32
10+
#include <AsyncTCP.h>
11+
#include <WiFi.h>
12+
#elif defined(ESP8266)
13+
#include <ESP8266WiFi.h>
14+
#include <ESPAsyncTCP.h>
15+
#elif defined(TARGET_RP2040)
16+
#include <WebServer.h>
17+
#include <WiFi.h>
18+
#endif
19+
20+
#include <ESPAsyncWebServer.h>
21+
22+
static AsyncWebServer server(80);
23+
24+
// basicAuth
25+
static AsyncAuthenticationMiddleware basicAuth;
26+
static AsyncAuthenticationMiddleware basicAuthHash;
27+
28+
// simple digest authentication
29+
static AsyncAuthenticationMiddleware digestAuth;
30+
static AsyncAuthenticationMiddleware digestAuthHash;
31+
32+
// complex authentication which adds request attributes for the next middlewares and handler
33+
static AsyncMiddlewareFunction complexAuth([](AsyncWebServerRequest *request, ArMiddlewareNext next) {
34+
if (!request->authenticate("user", "password")) {
35+
return request->requestAuthentication();
36+
}
37+
38+
// add attributes to the request for the next middlewares and handler
39+
request->setAttribute("user", "Mathieu");
40+
request->setAttribute("role", "staff");
41+
if (request->hasParam("token")) {
42+
request->setAttribute("token", request->getParam("token")->value().c_str());
43+
}
44+
45+
next();
46+
});
47+
48+
static AsyncAuthorizationMiddleware authz([](AsyncWebServerRequest *request) {
49+
return request->getAttribute("token") == "123";
50+
});
51+
52+
void setup() {
53+
Serial.begin(115200);
54+
55+
#ifndef CONFIG_IDF_TARGET_ESP32H2
56+
WiFi.mode(WIFI_AP);
57+
WiFi.softAP("esp-captive");
58+
#endif
59+
60+
// basic authentication
61+
basicAuth.setUsername("admin");
62+
basicAuth.setPassword("admin");
63+
basicAuth.setRealm("MyApp");
64+
basicAuth.setAuthFailureMessage("Authentication failed");
65+
basicAuth.setAuthType(AsyncAuthType::AUTH_BASIC);
66+
basicAuth.generateHash(); // precompute hash (optional but recommended)
67+
68+
// basic authentication with hash
69+
basicAuthHash.setUsername("admin");
70+
basicAuthHash.setPasswordHash("YWRtaW46YWRtaW4="); // BASE64(admin:admin)
71+
basicAuthHash.setRealm("MyApp");
72+
basicAuthHash.setAuthFailureMessage("Authentication failed");
73+
basicAuthHash.setAuthType(AsyncAuthType::AUTH_BASIC);
74+
75+
// digest authentication
76+
digestAuth.setUsername("admin");
77+
digestAuth.setPassword("admin");
78+
digestAuth.setRealm("MyApp");
79+
digestAuth.setAuthFailureMessage("Authentication failed");
80+
digestAuth.setAuthType(AsyncAuthType::AUTH_DIGEST);
81+
digestAuth.generateHash(); // precompute hash (optional but recommended)
82+
83+
// digest authentication with hash
84+
digestAuthHash.setUsername("admin");
85+
digestAuthHash.setPasswordHash("f499b71f9a36d838b79268e145e132f7"); // MD5(user:realm:pass)
86+
digestAuthHash.setRealm("MyApp");
87+
digestAuthHash.setAuthFailureMessage("Authentication failed");
88+
digestAuthHash.setAuthType(AsyncAuthType::AUTH_DIGEST);
89+
90+
// basic authentication method
91+
// curl -v -u admin:admin http://192.168.4.1/auth-basic
92+
server
93+
.on(
94+
"/auth-basic", HTTP_GET,
95+
[](AsyncWebServerRequest *request) {
96+
request->send(200, "text/plain", "Hello, world!");
97+
}
98+
)
99+
.addMiddleware(&basicAuth);
100+
101+
// basic authentication method with hash
102+
// curl -v -u admin:admin http://192.168.4.1/auth-basic-hash
103+
server
104+
.on(
105+
"/auth-basic-hash", HTTP_GET,
106+
[](AsyncWebServerRequest *request) {
107+
request->send(200, "text/plain", "Hello, world!");
108+
}
109+
)
110+
.addMiddleware(&basicAuthHash);
111+
112+
// digest authentication
113+
// curl -v -u admin:admin --digest http://192.168.4.1/auth-digest
114+
server
115+
.on(
116+
"/auth-digest", HTTP_GET,
117+
[](AsyncWebServerRequest *request) {
118+
request->send(200, "text/plain", "Hello, world!");
119+
}
120+
)
121+
.addMiddleware(&digestAuth);
122+
123+
// digest authentication with hash
124+
// curl -v -u admin:admin --digest http://192.168.4.1/auth-digest-hash
125+
server
126+
.on(
127+
"/auth-digest-hash", HTTP_GET,
128+
[](AsyncWebServerRequest *request) {
129+
request->send(200, "text/plain", "Hello, world!");
130+
}
131+
)
132+
.addMiddleware(&digestAuthHash);
133+
134+
// test digest auth custom authorization middleware
135+
// curl -v --digest -u user:password http://192.168.4.1/auth-custom?token=123 => OK
136+
// curl -v --digest -u user:password http://192.168.4.1/auth-custom?token=456 => 403
137+
// curl -v --digest -u user:FAILED http://192.168.4.1/auth-custom?token=456 => 401
138+
server
139+
.on(
140+
"/auth-custom", HTTP_GET,
141+
[](AsyncWebServerRequest *request) {
142+
String buffer = "Hello ";
143+
buffer.concat(request->getAttribute("user"));
144+
buffer.concat(" with role: ");
145+
buffer.concat(request->getAttribute("role"));
146+
request->send(200, "text/plain", buffer);
147+
}
148+
)
149+
.addMiddlewares({&complexAuth, &authz});
150+
151+
server.begin();
152+
}
153+
154+
// not needed
155+
void loop() {}

examples/CORS/CORS.ino

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// SPDX-License-Identifier: LGPL-3.0-or-later
2+
// Copyright 2016-2025 Hristo Gochkov, Mathieu Carbou, Emil Muratov
3+
4+
//
5+
// How to use CORS middleware
6+
//
7+
8+
#include <Arduino.h>
9+
#ifdef ESP32
10+
#include <AsyncTCP.h>
11+
#include <WiFi.h>
12+
#elif defined(ESP8266)
13+
#include <ESP8266WiFi.h>
14+
#include <ESPAsyncTCP.h>
15+
#elif defined(TARGET_RP2040)
16+
#include <WebServer.h>
17+
#include <WiFi.h>
18+
#endif
19+
20+
#include <ESPAsyncWebServer.h>
21+
22+
static AsyncWebServer server(80);
23+
static AsyncCorsMiddleware cors;
24+
25+
void setup() {
26+
Serial.begin(115200);
27+
28+
#ifndef CONFIG_IDF_TARGET_ESP32H2
29+
WiFi.mode(WIFI_AP);
30+
WiFi.softAP("esp-captive");
31+
#endif
32+
33+
cors.setOrigin("http://192.168.4.1");
34+
cors.setMethods("POST, GET, OPTIONS, DELETE");
35+
cors.setHeaders("X-Custom-Header");
36+
cors.setAllowCredentials(false);
37+
cors.setMaxAge(600);
38+
39+
server.addMiddleware(&cors);
40+
41+
// Test CORS preflight request
42+
// curl -v -X OPTIONS -H "origin: http://192.168.4.1" http://192.168.4.1/cors
43+
//
44+
// Test CORS request
45+
// curl -v -H "origin: http://192.168.4.1" http://192.168.4.1/cors
46+
//
47+
// Test non-CORS request
48+
// curl -v http://192.168.4.1/cors
49+
//
50+
server.on("/cors", HTTP_GET, [](AsyncWebServerRequest *request) {
51+
request->send(200, "text/plain", "Hello, world!");
52+
});
53+
54+
server.begin();
55+
}
56+
57+
// not needed
58+
void loop() {}

examples/CaptivePortal/CaptivePortal.ino

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
#endif
1515
#include "ESPAsyncWebServer.h"
1616

17-
DNSServer dnsServer;
18-
AsyncWebServer server(80);
17+
static DNSServer dnsServer;
18+
static AsyncWebServer server(80);
1919

2020
class CaptiveRequestHandler : public AsyncWebHandler {
2121
public:
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// SPDX-License-Identifier: LGPL-3.0-or-later
2+
// Copyright 2016-2025 Hristo Gochkov, Mathieu Carbou, Emil Muratov
3+
4+
//
5+
// Shows how to catch all requests and send a 404 Not Found response
6+
//
7+
8+
#include <Arduino.h>
9+
#ifdef ESP32
10+
#include <AsyncTCP.h>
11+
#include <WiFi.h>
12+
#elif defined(ESP8266)
13+
#include <ESP8266WiFi.h>
14+
#include <ESPAsyncTCP.h>
15+
#elif defined(TARGET_RP2040)
16+
#include <WebServer.h>
17+
#include <WiFi.h>
18+
#endif
19+
20+
#include <ESPAsyncWebServer.h>
21+
22+
static AsyncWebServer server(80);
23+
24+
static const char *htmlContent PROGMEM = R"(
25+
<!DOCTYPE html>
26+
<html>
27+
<head>
28+
<title>Sample HTML</title>
29+
</head>
30+
<body>
31+
<h1>Hello, World!</h1>
32+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
33+
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
34+
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
35+
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
36+
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
37+
dapibus elit, id varius sem dui id lacus.</p>
38+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
39+
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
40+
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
41+
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
42+
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
43+
dapibus elit, id varius sem dui id lacus.</p>
44+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
45+
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
46+
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
47+
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
48+
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
49+
dapibus elit, id varius sem dui id lacus.</p>
50+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
51+
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
52+
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
53+
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
54+
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
55+
dapibus elit, id varius sem dui id lacus.</p>
56+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
57+
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
58+
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
59+
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
60+
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
61+
dapibus elit, id varius sem dui id lacus.</p>
62+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
63+
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
64+
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
65+
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
66+
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
67+
dapibus elit, id varius sem dui id lacus.</p>
68+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
69+
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
70+
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
71+
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
72+
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
73+
dapibus elit, id varius sem dui id lacus.</p>
74+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
75+
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
76+
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
77+
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
78+
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
79+
dapibus elit, id varius sem dui id lacus.</p>
80+
</body>
81+
</html>
82+
)";
83+
84+
static const size_t htmlContentLength = strlen_P(htmlContent);
85+
86+
void setup() {
87+
Serial.begin(115200);
88+
89+
#ifndef CONFIG_IDF_TARGET_ESP32H2
90+
WiFi.mode(WIFI_AP);
91+
WiFi.softAP("esp-captive");
92+
#endif
93+
94+
// curl -v http://192.168.4.1/
95+
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
96+
// need to cast to uint8_t*
97+
// if you do not, the const char* will be copied in a temporary String buffer
98+
request->send(200, "text/html", (uint8_t *)htmlContent, htmlContentLength);
99+
});
100+
101+
// catch any request, and send a 404 Not Found response
102+
// except for /game_log which is handled by onRequestBody
103+
//
104+
// curl -v http://192.168.4.1/foo
105+
//
106+
server.onNotFound([](AsyncWebServerRequest *request) {
107+
if (request->url() == "/game_log") {
108+
return; // response object already created by onRequestBody
109+
}
110+
111+
request->send(404, "text/plain", "Not found");
112+
});
113+
114+
// See: https://github.com/ESP32Async/ESPAsyncWebServer/issues/6
115+
// catch any POST request and send a 200 OK response
116+
//
117+
// curl -v -X POST http://192.168.4.1/game_log -H "Content-Type: application/json" -d '{"game": "test"}'
118+
//
119+
server.onRequestBody([](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {
120+
if (request->url() == "/game_log") {
121+
request->send(200, "application/json", "{\"status\":\"OK\"}");
122+
}
123+
});
124+
125+
server.begin();
126+
}
127+
128+
// not needed
129+
void loop() {}

0 commit comments

Comments
 (0)