Skip to content

Commit 0bfc9a5

Browse files
committed
unify AsyncBasicResponse::_ack code with AsyncAbstractResponse::_ack
1 parent 55d45c1 commit 0bfc9a5

File tree

3 files changed

+88
-58
lines changed

3 files changed

+88
-58
lines changed

src/ESPAsyncWebServer.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,6 +1165,17 @@ class AsyncWebServerResponse {
11651165
virtual bool _failed() const;
11661166
virtual bool _sourceValid() const;
11671167
virtual void _respond(AsyncWebServerRequest *request);
1168+
1169+
/**
1170+
* @brief write next portion of response data to send buffs
1171+
* this method (re)fills tcp send buffers, it could be called either at will
1172+
* or from a tcp_recv/tcp_poll callbacks from AsyncTCP
1173+
*
1174+
* @param request - used to access client object
1175+
* @param len - size of acknowledged data from the remote side (TCP window update, not TCP ack!)
1176+
* @param time - time passed between last sent and received packet
1177+
* @return size_t amount of response data placed to TCP send buffs for delivery (defined by sdkconfig value CONFIG_LWIP_TCP_SND_BUF_DEFAULT)
1178+
*/
11681179
virtual size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time);
11691180
};
11701181

src/WebResponseImpl.h

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,34 @@
2525
class AsyncBasicResponse : public AsyncWebServerResponse {
2626
private:
2727
String _content;
28+
// buffer to accumulate all response headers
29+
String _assembled_headers;
30+
// amount of headers buffer writtent to sockbuff
31+
size_t _writtenHeadersLength{0};
2832

2933
public:
3034
explicit AsyncBasicResponse(int code, const char *contentType = asyncsrv::empty, const char *content = asyncsrv::empty);
3135
AsyncBasicResponse(int code, const String &contentType, const String &content = emptyString)
3236
: AsyncBasicResponse(code, contentType.c_str(), content.c_str()) {}
3337
void _respond(AsyncWebServerRequest *request) override final;
34-
size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time) override final;
38+
size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time) override final { return write_send_buffs(request, len, time); };
3539
bool _sourceValid() const override final {
3640
return true;
3741
}
42+
43+
protected:
44+
/**
45+
* @brief write next portion of response data to send buffs
46+
* this method (re)fills tcp send buffers, it could be called either at will
47+
* or from a tcp_recv/tcp_poll callbacks from AsyncTCP
48+
*
49+
* @param request - used to access client object
50+
* @param len - size of acknowledged data from the remote side (TCP window update, not TCP ack!)
51+
* @param time - time passed between last sent and received packet
52+
* @return size_t amount of response data placed to TCP send buffs for delivery (defined by sdkconfig value CONFIG_LWIP_TCP_SND_BUF_DEFAULT)
53+
*/
54+
size_t write_send_buffs(AsyncWebServerRequest *request, size_t len, uint32_t time);
55+
3856
};
3957

4058
class AsyncAbstractResponse : public AsyncWebServerResponse {
@@ -48,7 +66,7 @@ class AsyncAbstractResponse : public AsyncWebServerResponse {
4866
// buffer to accumulate all response headers
4967
String _assembled_headers;
5068
// amount of headers buffer writtent to sockbuff
51-
size_t _assembled_headers_written{0};
69+
size_t _writtenHeadersLength{0};
5270
// Data is inserted into cache at begin().
5371
// This is inefficient with vector, but if we use some other container,
5472
// we won't be able to access it as contiguous array of bytes when reading from it,
@@ -63,12 +81,23 @@ class AsyncAbstractResponse : public AsyncWebServerResponse {
6381

6482
protected:
6583
AwsTemplateProcessor _callback;
84+
/**
85+
* @brief write next portion of response data to send buffs
86+
* this method (re)fills tcp send buffers, it could be called either at will
87+
* or from a tcp_recv/tcp_poll callbacks from AsyncTCP
88+
*
89+
* @param request - used to access client object
90+
* @param len - size of acknowledged data from the remote side (TCP window update, not TCP ack!)
91+
* @param time - time passed between last sent and received packet
92+
* @return size_t amount of response data placed to TCP send buffs for delivery (defined by sdkconfig value CONFIG_LWIP_TCP_SND_BUF_DEFAULT)
93+
*/
94+
size_t write_send_buffs(AsyncWebServerRequest *request, size_t len, uint32_t time);
6695

6796
public:
6897
AsyncAbstractResponse(AwsTemplateProcessor callback = nullptr);
6998
virtual ~AsyncAbstractResponse() {}
7099
void _respond(AsyncWebServerRequest *request) override final;
71-
size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time) override final;
100+
size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time) override final { return write_send_buffs(request, len, time); };
72101
virtual bool _sourceValid() const {
73102
return false;
74103
}

src/WebResponses.cpp

Lines changed: 45 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,6 @@ bool AsyncWebServerResponse::_sourceValid() const {
243243
}
244244
void AsyncWebServerResponse::_respond(AsyncWebServerRequest *request) {
245245
_state = RESPONSE_END;
246-
request->client()->close();
247246
}
248247
size_t AsyncWebServerResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time) {
249248
(void)request;
@@ -270,64 +269,55 @@ AsyncBasicResponse::AsyncBasicResponse(int code, const char *contentType, const
270269

271270
void AsyncBasicResponse::_respond(AsyncWebServerRequest *request) {
272271
_state = RESPONSE_HEADERS;
273-
String out;
274-
_assembleHead(out, request->version());
275-
size_t outLen = out.length();
276-
size_t space = request->client()->space();
277-
if (!_contentLength && space >= outLen) {
278-
_writtenLength += request->client()->write(out.c_str(), outLen);
279-
_state = RESPONSE_WAIT_ACK;
280-
} else if (_contentLength && space >= outLen + _contentLength) {
281-
out += _content;
282-
outLen += _contentLength;
283-
_writtenLength += request->client()->write(out.c_str(), outLen);
284-
_state = RESPONSE_WAIT_ACK;
285-
} else if (space && space < outLen) {
286-
String partial = out.substring(0, space);
287-
_content = out.substring(space) + _content;
288-
_contentLength += outLen - space;
289-
_writtenLength += request->client()->write(partial.c_str(), partial.length());
290-
_state = RESPONSE_CONTENT;
291-
} else if (space > outLen && space < (outLen + _contentLength)) {
292-
size_t shift = space - outLen;
293-
outLen += shift;
294-
_sentLength += shift;
295-
out += _content.substring(0, shift);
296-
_content = _content.substring(shift);
297-
_writtenLength += request->client()->write(out.c_str(), outLen);
298-
_state = RESPONSE_CONTENT;
299-
} else {
300-
_content = out + _content;
301-
_contentLength += outLen;
302-
_state = RESPONSE_CONTENT;
303-
}
272+
_assembleHead(_assembled_headers, request->version());
273+
_ack(request, 0, 0);
304274
}
305275

306-
size_t AsyncBasicResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time) {
276+
size_t AsyncBasicResponse::write_send_buffs(AsyncWebServerRequest *request, size_t len, uint32_t time) {
307277
(void)time;
278+
279+
// this is not functionally needed in AsyncBasicResponse itself, but kept for compatibility if some of the derived classes are rely on it somehow
308280
_ackedLength += len;
309-
if (_state == RESPONSE_CONTENT) {
310-
size_t available = _contentLength - _sentLength;
311-
size_t space = request->client()->space();
312-
// we can fit in this packet
313-
if (space > available) {
314-
_writtenLength += request->client()->write(_content.c_str(), available);
315-
_content = emptyString;
316-
_state = RESPONSE_WAIT_ACK;
317-
return available;
281+
size_t payloadlen{0}; // amount of data to be written to tcp sockbuff during this call, used as return value of this method
282+
283+
// send http headers first
284+
if (_state == RESPONSE_HEADERS) {
285+
// copy headers buffer to sock buffer
286+
size_t const pcb_written = request->client()->add(_assembled_headers.c_str() + _writtenHeadersLength, _assembled_headers.length() - _writtenHeadersLength);
287+
_writtenLength += pcb_written;
288+
_writtenHeadersLength += pcb_written;
289+
if (_writtenHeadersLength < _assembled_headers.length()){
290+
// we were not able to fit all headers in current buff, send this part here and return later for the rest
291+
if (!request->client()->send()){
292+
// something is wrong, what should we do here?
293+
request->client()->close();
294+
return 0;
295+
}
296+
return pcb_written;
318297
}
319-
// send some data, the rest on ack
320-
String out = _content.substring(0, space);
321-
_content = _content.substring(space);
322-
_sentLength += space;
323-
_writtenLength += request->client()->write(out.c_str(), space);
324-
return space;
325-
} else if (_state == RESPONSE_WAIT_ACK) {
326-
if (_ackedLength >= _writtenLength) {
298+
// otherwise we've added all the (remainder) headers in current buff, go on with content
299+
_state = RESPONSE_CONTENT;
300+
payloadlen += pcb_written;
301+
_assembled_headers = String(); // clear
302+
}
303+
304+
if (_state == RESPONSE_CONTENT) {
305+
size_t const pcb_written = request->client()->write(_content.c_str() + _sentLength, _content.length() - _sentLength);
306+
_writtenLength += pcb_written; // total written data (hdrs + body)
307+
_sentLength += pcb_written; // body written data
308+
payloadlen += pcb_written; // data writtent in current buff
309+
if (_sentLength >= _content.length()){
310+
// we've just sent all the (remainder) data in current buff, complete the response
327311
_state = RESPONSE_END;
328312
}
329313
}
330-
return 0;
314+
315+
// implicit complete
316+
if (_state == RESPONSE_WAIT_ACK) {
317+
_state = RESPONSE_END;
318+
}
319+
320+
return payloadlen;
331321
}
332322

333323
/*
@@ -350,7 +340,7 @@ void AsyncAbstractResponse::_respond(AsyncWebServerRequest *request) {
350340
_ack(request, 0, 0);
351341
}
352342

353-
size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time) {
343+
size_t AsyncAbstractResponse::write_send_buffs(AsyncWebServerRequest *request, size_t len, uint32_t time) {
354344
(void)time;
355345
if (!_sourceValid()) {
356346
_state = RESPONSE_FAILED;
@@ -393,10 +383,10 @@ size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest *request, size_t len, u
393383
// send http headers first
394384
if (_state == RESPONSE_HEADERS) {
395385
// copy headers buffer to sock buffer
396-
size_t const pcb_written = request->client()->add(_assembled_headers.c_str() + _assembled_headers_written, _assembled_headers.length() - _assembled_headers_written);
386+
size_t const pcb_written = request->client()->add(_assembled_headers.c_str() + _writtenHeadersLength, _assembled_headers.length() - _writtenHeadersLength);
397387
_writtenLength += pcb_written;
398-
_assembled_headers_written += pcb_written;
399-
if (_assembled_headers_written < _assembled_headers.length()){
388+
_writtenHeadersLength += pcb_written;
389+
if (_writtenHeadersLength < _assembled_headers.length()){
400390
// we were not able to fit all headers in current buff, send this part here and return later for the rest
401391
#if ASYNCWEBSERVER_USE_CHUNK_INFLIGHT
402392
_in_flight += pcb_written;

0 commit comments

Comments
 (0)