Skip to content

Commit f4f8762

Browse files
committed
Add chunkedResponseModeStart, sendChunk, chunkedResponseFinalize
to WebServer library for chunked HTTP responses
1 parent ea382df commit f4f8762

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

libraries/WebServer/src/WebServer.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,78 @@ void WebServer::enableETag(bool enable, ETagFunction fn) {
551551
_eTagFunction = fn;
552552
}
553553

554+
void WebServer::chunkResponseBegin(const char* contentType) {
555+
if (_chunkedResponseActive) {
556+
log_e("Already in chunked response mode");
557+
return;
558+
}
559+
560+
if (strchr(contentType, '\r') || strchr(contentType, '\n')) {
561+
log_e("Invalid character in content type");
562+
return;
563+
}
564+
565+
_chunkedResponseActive = true;
566+
_chunkedClient = _currentClient;
567+
568+
_contentLength = CONTENT_LENGTH_UNKNOWN;
569+
570+
String header;
571+
_prepareHeader(header, 200, contentType, 0);
572+
_currentClientWrite(header.c_str(), header.length());
573+
574+
_chunkedResponseActive = true;
575+
_chunkedClient = _currentClient;
576+
}
577+
578+
void WebServer::chunkWrite(const char* data, size_t length) {
579+
if (!_chunkedResponseActive)
580+
{
581+
log_e("Chunked response has not been started");
582+
return;
583+
}
584+
585+
char chunkSize[11];
586+
snprintf(chunkSize, sizeof(chunkSize), "%zx\r\n", length);
587+
588+
if (_chunkedClient.write(chunkSize) != strlen(chunkSize)) {
589+
log_e("Failed to write chunk size");
590+
_chunkedResponseActive = false;
591+
return;
592+
}
593+
594+
if (_chunkedClient.write((const uint8_t*)data, length) != length) {
595+
log_e("Failed to write chunk data");
596+
_chunkedResponseActive = false;
597+
return;
598+
}
599+
600+
if (_chunkedClient.write("\r\n") != 2) {
601+
log_e("Failed to write chunk terminator");
602+
_chunkedResponseActive = false;
603+
return;
604+
}
605+
}
606+
607+
void WebServer::chunkResponseEnd() {
608+
if (!_chunkedResponseActive)
609+
{
610+
log_e("Chunked response has not been started");
611+
return;
612+
}
613+
614+
if (_chunkedClient.write("0\r\n\r\n", 5) != 5) {
615+
log_e("Failed to write terminating chunk");
616+
}
617+
618+
_chunkedClient.flush();
619+
_chunkedResponseActive = false;
620+
_chunked = false;
621+
_chunkedClient = NetworkClient();
622+
623+
_clearResponseHeaders();
624+
}
625+
554626
void WebServer::_prepareHeader(String &response, int code, const char *content_type, size_t contentLength) {
555627
_responseCode = code;
556628

libraries/WebServer/src/WebServer.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ class WebServer {
115115
const String AuthTypeDigest = F("Digest");
116116
const String AuthTypeBasic = F("Basic");
117117

118+
void chunkResponseBegin(const char* contentType = "text/plain");
119+
void chunkWrite(const char* data, size_t length);
120+
void chunkResponseEnd();
121+
118122
/* Callbackhandler for authentication. The extra parameters depend on the
119123
* HTTPAuthMethod mode:
120124
*
@@ -241,6 +245,10 @@ class WebServer {
241245

242246
static String responseCodeToString(int code);
243247

248+
private:
249+
bool _chunkedResponseActive = false;
250+
NetworkClient _chunkedClient; // Store by value, no dangling pointer
251+
244252
protected:
245253
virtual size_t _currentClientWrite(const char *b, size_t l) {
246254
return _currentClient.write(b, l);

0 commit comments

Comments
 (0)