Skip to content

Commit 55214ae

Browse files
committed
Added back MRE
1 parent 0b6bab6 commit 55214ae

File tree

1 file changed

+70
-16
lines changed

1 file changed

+70
-16
lines changed

examples/LargeResponse/LargeResponse.ino

Lines changed: 70 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,64 @@ private:
6565
size_t _sent = 0;
6666
};
6767

68+
// Code to reproduce issues:
69+
// - https://github.com/ESP32Async/ESPAsyncWebServer/issues/242
70+
// - https://github.com/ESP32Async/ESPAsyncWebServer/issues/315
71+
//
72+
// https://github.com/ESP32Async/ESPAsyncWebServer/pull/317#issuecomment-3421141039
73+
//
74+
// I cracked it.
75+
// So this is how it works:
76+
// That space that _tcp is writing to identified by CONFIG_TCP_SND_BUF_DEFAULT (and is value-matching with default TCP windows size which is very confusing itself).
77+
// The space returned by client()->write() and client->space() somehow might not be atomically/thread synced (had not dived that deep yet). So if first call to _fillBuffer is done via user-code thread and ended up with some small amount of data consumed and second one is done by _poll or _ack? returns full size again! This is where old code fails.
78+
// If you change your class this way it will fail 100%.
79+
class CustomResponseMRE : public AsyncAbstractResponse {
80+
public:
81+
explicit CustomResponseMRE() {
82+
_code = 200;
83+
_contentType = "text/plain";
84+
_sendContentLength = false;
85+
// add some useless headers
86+
addHeader("Clear-Site-Data", "Clears browsing data (e.g., cookies, storage, cache) associated with the requesting website.");
87+
addHeader(
88+
"No-Vary-Search", "Specifies a set of rules that define how a URL's query parameters will affect cache matching. These rules dictate whether the same "
89+
"URL with different URL parameters should be saved as separate browser cache entries"
90+
);
91+
}
92+
93+
bool _sourceValid() const override {
94+
return true;
95+
}
96+
97+
size_t _fillBuffer(uint8_t *buf, size_t buflen) override {
98+
if (fillChar == NULL) {
99+
fillChar = 'A';
100+
return RESPONSE_TRY_AGAIN;
101+
}
102+
if (_sent == RESPONSE_TRY_AGAIN) {
103+
Serial.println("Simulating temporary unavailability of data...");
104+
_sent = 0;
105+
return RESPONSE_TRY_AGAIN;
106+
}
107+
size_t remaining = totalResponseSize - _sent;
108+
if (remaining == 0) {
109+
return 0;
110+
}
111+
if (buflen > remaining) {
112+
buflen = remaining;
113+
}
114+
Serial.printf("Filling '%c' @ sent: %u, buflen: %u\n", fillChar, _sent, buflen);
115+
std::fill_n(buf, buflen, static_cast<uint8_t>(fillChar));
116+
_sent += buflen;
117+
fillChar = (fillChar == 'Z') ? 'A' : fillChar + 1;
118+
return buflen;
119+
}
120+
121+
private:
122+
char fillChar = NULL;
123+
size_t _sent = 0;
124+
};
125+
68126
void setup() {
69127
Serial.begin(115200);
70128

@@ -77,14 +135,7 @@ void setup() {
77135
//
78136
// curl -v http://192.168.4.1/1 | grep -o '.' | sort | uniq -c
79137
//
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
138+
// Should output 16000 and a distribution of letters which is the same in ESP32 logs and console
88139
//
89140
server.on("/1", HTTP_GET, [](AsyncWebServerRequest *request) {
90141
fillChar = 'A';
@@ -103,19 +154,22 @@ void setup() {
103154
//
104155
// curl -v http://192.168.4.1/2 | grep -o '.' | sort | uniq -c
105156
//
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
157+
// Should output 16000 and a distribution of letters which is the same in ESP32 logs and console
114158
//
115159
server.on("/2", HTTP_GET, [](AsyncWebServerRequest *request) {
116160
request->send(new CustomResponse());
117161
});
118162

163+
// Example to use a AsyncAbstractResponse
164+
//
165+
// curl -v http://192.168.4.1/3 | grep -o '.' | sort | uniq -c
166+
//
167+
// Should output 16000 and a distribution of letters which is the same in ESP32 logs and console
168+
//
169+
server.on("/3", HTTP_GET, [](AsyncWebServerRequest *request) {
170+
request->send(new CustomResponseMRE());
171+
});
172+
119173
server.begin();
120174
}
121175

0 commit comments

Comments
 (0)