for response payloads with unknown length or length larger than TCP_WND we need to control AsyncTCP's queue and in-flight fragmentation.
Either user callback could fill buffer with very small chunks or long running large response could receive a lot of poll() calls here,
both could flood asynctcp's queue with large number of events to handle and fragment socket buffer space for large responses.
Let's ignore polled acks and acks in case when available window size is less than our used buffer size since we won't be able to fill and send it whole
That way we could balance on having at least half tcp win in-flight while minimizing send/ack events in asynctcp Q
This could decrease sustained bandwidth for one single connection but would drastically improve parallelism and equalize bandwidth sharing
*/
// return a credit for each chunk of acked data (polls does not give any credits)
if (len) {
++_in_flight_credit;
_in_flight -= std::min(len, _in_flight);
}
if (_chunked || !_sendContentLength || (_sentLength > CONFIG_LWIP_TCP_WND_DEFAULT)) {
if (!_in_flight_credit || (ASYNC_RESPONCE_BUFF_SIZE > request->client()->space())) {
// async_ws_log_d("defer user call in_flight:%u, tcpwin:%u", _in_flight, request->client()->space());
// take the credit back since we are ignoring this ack and rely on other inflight data acks
if (len) {
--_in_flight_credit;
}
return0;
}
}
#endif
// this is not functionally needed in AsyncAbstractResponse itself, but kept for compatibility if some of the derived classes are rely on it somehow
_ackedLength += len;
size_t payloadlen{0}; // amount of data to be written to tcp sockbuff during this call, used as return value of this method
// available window size is not enough to send a new chunk sized half of tcp mss, let's wait for better chance and reduce pressure to AsyncTCP's event Q
break;
}
if (!_send_buffer) {
auto p = new (std::nothrow) std::array<uint8_t, ASYNC_RESPONCE_BUFF_SIZE>;
if (p) {
_send_buffer.reset(p);
_send_buffer_len = _send_buffer_offset = 0;
} else {
break; // OOM
}
}
if (_chunked) {
// HTTP 1.1 allows leading zeros in chunk length. Or spaces may be added.
// See https://datatracker.ietf.org/doc/html/rfc9112#section-7.1
size_tconst readLen =
_fillBufferAndProcessTemplates(_send_buffer->data() + 6, std::min(_send_buffer->size(), tcp_win) - 8); // reserve 8 bytes for chunk size data
if (readLen != RESPONSE_TRY_AGAIN) {
// Write 4 hex digits directly without null terminator