Skip to content

Commit b67f0e9

Browse files
Merge pull request #317 from ESP32Async/examples/LargeResponse
Added LargeResponse example
2 parents cf4f122 + a3f612a commit b67f0e9

File tree

3 files changed

+126
-1
lines changed

3 files changed

+126
-1
lines changed

examples/ChunkResponse/ChunkResponse.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ void setup() {
9494
// first time: serves the file and cache headers
9595
// curl -N -v http://192.168.4.1/ --output -
9696
//
97-
// secodn time: serves 304
97+
// second time: serves 304
9898
// curl -N -v -H "if-none-match: 4272" http://192.168.4.1/ --output -
9999
//
100100
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// SPDX-License-Identifier: LGPL-3.0-or-later
2+
// Copyright 2016-2025 Hristo Gochkov, Mathieu Carbou, Emil Muratov
3+
4+
//
5+
// Example to send a large response and control the filling of the buffer.
6+
//
7+
// This is also a MRE for:
8+
// - https://github.com/ESP32Async/ESPAsyncWebServer/issues/242
9+
// - https://github.com/ESP32Async/ESPAsyncWebServer/issues/315
10+
//
11+
12+
#include <Arduino.h>
13+
#if defined(ESP32) || defined(LIBRETINY)
14+
#include <AsyncTCP.h>
15+
#include <WiFi.h>
16+
#elif defined(ESP8266)
17+
#include <ESP8266WiFi.h>
18+
#include <ESPAsyncTCP.h>
19+
#elif defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350)
20+
#include <RPAsyncTCP.h>
21+
#include <WiFi.h>
22+
#endif
23+
24+
#include <ESPAsyncWebServer.h>
25+
26+
static AsyncWebServer server(80);
27+
28+
static const size_t totalResponseSize = 16 * 1000; // 16 KB
29+
static char fillChar = 'A';
30+
31+
class CustomResponse : public AsyncAbstractResponse {
32+
public:
33+
explicit CustomResponse() {
34+
_code = 200;
35+
_contentType = "text/plain";
36+
_sendContentLength = false;
37+
}
38+
39+
bool _sourceValid() const override {
40+
return true;
41+
}
42+
43+
size_t _fillBuffer(uint8_t *buf, size_t buflen) override {
44+
if (_sent == RESPONSE_TRY_AGAIN) {
45+
Serial.println("Simulating temporary unavailability of data...");
46+
_sent = 0;
47+
return RESPONSE_TRY_AGAIN;
48+
}
49+
size_t remaining = totalResponseSize - _sent;
50+
if (remaining == 0) {
51+
return 0;
52+
}
53+
if (buflen > remaining) {
54+
buflen = remaining;
55+
}
56+
Serial.printf("Filling '%c' @ sent: %u, buflen: %u\n", fillChar, _sent, buflen);
57+
std::fill_n(buf, buflen, static_cast<uint8_t>(fillChar));
58+
_sent += buflen;
59+
fillChar = (fillChar == 'Z') ? 'A' : fillChar + 1;
60+
return buflen;
61+
}
62+
63+
private:
64+
char fillChar = 'A';
65+
size_t _sent = 0;
66+
};
67+
68+
void setup() {
69+
Serial.begin(115200);
70+
71+
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI || CONFIG_ESP32_WIFI_ENABLED
72+
WiFi.mode(WIFI_AP);
73+
WiFi.softAP("esp-captive");
74+
#endif
75+
76+
// Example to use a AwsResponseFiller
77+
//
78+
// curl -v http://192.168.4.1/1 | grep -o '.' | sort | uniq -c
79+
//
80+
// Should output 16000 and the counts for each character from A to D
81+
//
82+
// Console:
83+
//
84+
// Filling 'A' @ index: 0, maxLen: 5652, toSend: 5652
85+
// Filling 'B' @ index: 5652, maxLen: 4308, toSend: 4308
86+
// Filling 'C' @ index: 9960, maxLen: 2888, toSend: 2888
87+
// Filling 'D' @ index: 12848, maxLen: 3152, toSend: 3152
88+
//
89+
server.on("/1", HTTP_GET, [](AsyncWebServerRequest *request) {
90+
fillChar = 'A';
91+
AsyncWebServerResponse *response = request->beginResponse("text/plain", totalResponseSize, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
92+
size_t remaining = totalResponseSize - index;
93+
size_t toSend = (remaining < maxLen) ? remaining : maxLen;
94+
Serial.printf("Filling '%c' @ index: %u, maxLen: %u, toSend: %u\n", fillChar, index, maxLen, toSend);
95+
std::fill_n(buffer, toSend, static_cast<uint8_t>(fillChar));
96+
fillChar = (fillChar == 'Z') ? 'A' : fillChar + 1;
97+
return toSend;
98+
});
99+
request->send(response);
100+
});
101+
102+
// Example to use a AsyncAbstractResponse
103+
//
104+
// curl -v http://192.168.4.1/2 | grep -o '.' | sort | uniq -c
105+
//
106+
// Should output 16000
107+
//
108+
// Console:
109+
//
110+
// Filling 'A' @ sent: 0, buflen: 5675
111+
// Filling 'B' @ sent: 5675, buflen: 4308
112+
// Filling 'C' @ sent: 9983, buflen: 5760
113+
// Filling 'D' @ sent: 15743, buflen: 257
114+
//
115+
server.on("/2", HTTP_GET, [](AsyncWebServerRequest *request) {
116+
request->send(new CustomResponse());
117+
});
118+
119+
server.begin();
120+
}
121+
122+
void loop() {
123+
delay(100);
124+
}

platformio.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ lib_dir = .
1414
; src_dir = examples/FlashResponse
1515
; src_dir = examples/HeaderManipulation
1616
; src_dir = examples/Json
17+
; src_dir = examples/LargeResponse
1718
; src_dir = examples/Logging
1819
; src_dir = examples/MessagePack
1920
; src_dir = examples/Middleware

0 commit comments

Comments
 (0)