@@ -551,6 +551,76 @@ void WebServer::enableETag(bool enable, ETagFunction fn) {
551551 _eTagFunction = fn;
552552}
553553
554+ void WebServer::chunkedResponseModeStart (const char * contentType) {
555+ if (_chunkedResponseActive) {
556+ log_e (" Already in chunked response mode" );
557+ return ;
558+ }
559+
560+ // Validate contentType for CRLF injection
561+ if (strchr (contentType, ' \r ' ) || strchr (contentType, ' \n ' )) {
562+ log_e (" Invalid character in content type" );
563+ return ;
564+ }
565+
566+ // Tell framework response length is unknown (chunked)
567+ _contentLength = CONTENT_LENGTH_UNKNOWN;
568+
569+ // Prepare and send headers properly once
570+ String header;
571+ _prepareHeader (header, 200 , contentType, 0 );
572+ _currentClientWrite (header.c_str (), header.length ());
573+
574+ // Activate chunked mode and store client by value (safe)
575+ _chunkedResponseActive = true ;
576+ _chunkedClient = _currentClient;
577+ }
578+
579+ void WebServer::sendChunk (const char * data, size_t length) {
580+ if (!_chunkedResponseActive) return ;
581+
582+ char chunkSize[11 ]; // Enough for size_t in hex + CRLF + null
583+ snprintf (chunkSize, sizeof (chunkSize), " %zx\r\n " , length);
584+
585+ if (_chunkedClient.write (chunkSize) != strlen (chunkSize)) {
586+ log_e (" Failed to write chunk size" );
587+ _chunkedResponseActive = false ;
588+ return ;
589+ }
590+
591+ if (_chunkedClient.write ((const uint8_t *)data, length) != length) {
592+ log_e (" Failed to write chunk data" );
593+ _chunkedResponseActive = false ;
594+ return ;
595+ }
596+
597+ if (_chunkedClient.write (" \r\n " ) != 2 ) {
598+ log_e (" Failed to write chunk terminator" );
599+ _chunkedResponseActive = false ;
600+ return ;
601+ }
602+
603+ // Optionally flush here or less frequently for better performance
604+ // _chunkedClient.flush();
605+ }
606+
607+ void WebServer::chunkedResponseFinalize () {
608+ if (!_chunkedResponseActive) return ;
609+
610+ if (_chunkedClient.write (" 0\r\n\r\n " , 5 ) != 5 ) {
611+ log_e (" Failed to write terminating chunk" );
612+ }
613+
614+ _chunkedClient.flush ();
615+
616+ // Do NOT call stop() to allow framework to handle connection lifetime
617+ _chunkedResponseActive = false ;
618+ _chunked = false ;
619+ _chunkedClient = NetworkClient ();
620+
621+ _clearResponseHeaders (); // Clear headers set by sendHeader()
622+ }
623+
554624void WebServer::_prepareHeader (String &response, int code, const char *content_type, size_t contentLength) {
555625 _responseCode = code;
556626
0 commit comments