@@ -125,9 +125,8 @@ const char* AsyncWebServerResponse::responseCodeToString(int code) {
125125 return T_HTTP_CODE_ANY;
126126 }
127127}
128- #else // ESP8266
129- const __FlashStringHelper* AsyncWebServerResponse::responseCodeToString (int code)
130- {
128+ #else // ESP8266
129+ const __FlashStringHelper* AsyncWebServerResponse::responseCodeToString (int code) {
131130 switch (code) {
132131 case 100 :
133132 return FPSTR (T_HTTP_CODE_100);
@@ -230,12 +229,12 @@ void AsyncWebServerResponse::setCode(int code) {
230229}
231230
232231void AsyncWebServerResponse::setContentLength (size_t len) {
233- if (_state == RESPONSE_SETUP)
232+ if (_state == RESPONSE_SETUP && addHeader (T_Content_Length, len, true ) )
234233 _contentLength = len;
235234}
236235
237236void AsyncWebServerResponse::setContentType (const char * type) {
238- if (_state == RESPONSE_SETUP)
237+ if (_state == RESPONSE_SETUP && addHeader (T_Content_Type, type, true ) )
239238 _contentType = type;
240239}
241240
@@ -249,6 +248,11 @@ bool AsyncWebServerResponse::removeHeader(const char* name) {
249248 return false ;
250249}
251250
251+ const AsyncWebHeader* AsyncWebServerResponse::getHeader (const char * name) const {
252+ auto iter = std::find_if (std::begin (_headers), std::end (_headers), [&name](const AsyncWebHeader& header) { return header.name ().equalsIgnoreCase (name); });
253+ return (iter == std::end (_headers)) ? nullptr : &(*iter);
254+ }
255+
252256bool AsyncWebServerResponse::addHeader (const char * name, const char * value, bool replaceExisting) {
253257 for (auto i = _headers.begin (); i != _headers.end (); ++i) {
254258 if (i->name ().equalsIgnoreCase (name)) {
@@ -268,41 +272,56 @@ bool AsyncWebServerResponse::addHeader(const char* name, const char* value, bool
268272 return true ;
269273}
270274
271- String AsyncWebServerResponse::_assembleHead (uint8_t version) {
275+ void AsyncWebServerResponse::_assembleHead (String& buffer, uint8_t version) {
272276 if (version) {
273277 addHeader (T_Accept_Ranges, T_none, false );
274278 if (_chunked)
275279 addHeader (T_Transfer_Encoding, T_chunked, false );
276280 }
277- String out;
278- constexpr size_t bufSize = 300 ;
279- char buf[bufSize];
280281
281- #ifndef ESP8266
282- snprintf (buf, bufSize, " HTTP/1.%d %d %s\r\n " , version, _code, responseCodeToString (_code));
283- #else
284- snprintf_P (buf, bufSize, PSTR (" HTTP/1.%d %d %s\r\n " ), version, _code, String (responseCodeToString (_code)).c_str ());
285- #endif
286- out.concat (buf);
282+ if (_sendContentLength)
283+ addHeader (T_Content_Length, String (_contentLength), false );
287284
288- if (_sendContentLength) {
289- snprintf_P (buf, bufSize, PSTR ( " Content-Length: %d \r\n " ), _contentLength );
290- out. concat (buf);
291- }
292- if (_contentType. length ()) {
293- snprintf_P (buf, bufSize, PSTR ( " Content-Type: %s \r\n " ), _contentType. c_str ());
294- out. concat (buf);
295- }
285+ if (_contentType. length ())
286+ addHeader (T_Content_Type, _contentType. c_str ( ), false );
287+
288+ // precompute buffer size to avoid reallocations by String class
289+ size_t len = 0 ;
290+ len += 50 ; // HTTP/1.1 200 <reason> \r\n
291+ for ( const auto & header : _headers)
292+ len += header. name (). length () + header. value (). length () + 4 ;
296293
294+ // prepare buffer
295+ buffer.reserve (len);
296+
297+ // HTTP header
298+ #ifdef ESP8266
299+ buffer.concat (PSTR (" HTTP/1." ));
300+ #else
301+ buffer.concat (" HTTP/1." );
302+ #endif
303+ buffer.concat (version);
304+ buffer.concat (' ' );
305+ buffer.concat (_code);
306+ buffer.concat (' ' );
307+ buffer.concat (responseCodeToString (_code));
308+ buffer.concat (T_rn);
309+
310+ // Add headers
297311 for (const auto & header : _headers) {
298- snprintf_P (buf, bufSize, PSTR (" %s: %s\r\n " ), header.name ().c_str (), header.value ().c_str ());
299- out.concat (buf);
312+ buffer.concat (header.name ());
313+ #ifdef ESP8266
314+ buffer.concat (PSTR (" : " ));
315+ #else
316+ buffer.concat (" : " );
317+ #endif
318+ buffer.concat (header.value ());
319+ buffer.concat (T_rn);
300320 }
301321 _headers.clear ();
302322
303- out.concat (T_rn);
304- _headLength = out.length ();
305- return out;
323+ buffer.concat (T_rn);
324+ _headLength = buffer.length ();
306325}
307326
308327bool AsyncWebServerResponse::_started () const { return _state > RESPONSE_SETUP; }
@@ -337,7 +356,8 @@ AsyncBasicResponse::AsyncBasicResponse(int code, const char* contentType, const
337356
338357void AsyncBasicResponse::_respond (AsyncWebServerRequest* request) {
339358 _state = RESPONSE_HEADERS;
340- String out = _assembleHead (request->version ());
359+ String out;
360+ _assembleHead (out, request->version ());
341361 size_t outLen = out.length ();
342362 size_t space = request->client ()->space ();
343363 if (!_contentLength && space >= outLen) {
@@ -411,7 +431,7 @@ AsyncAbstractResponse::AsyncAbstractResponse(AwsTemplateProcessor callback) : _c
411431
412432void AsyncAbstractResponse::_respond (AsyncWebServerRequest* request) {
413433 addHeader (T_Connection, T_close, false );
414- _head = _assembleHead (request->version ());
434+ _assembleHead (_head, request->version ());
415435 _state = RESPONSE_HEADERS;
416436 _ack (request, 0 , 0 );
417437}
@@ -635,9 +655,9 @@ AsyncFileResponse::~AsyncFileResponse() {
635655void AsyncFileResponse::_setContentTypeFromPath (const String& path) {
636656#if HAVE_EXTERN_GET_Content_Type_FUNCTION
637657 #ifndef ESP8266
638- extern const char * getContentType (const String& path);
658+ extern const char * getContentType (const String& path);
639659 #else
640- extern const __FlashStringHelper* getContentType (const String& path);
660+ extern const __FlashStringHelper* getContentType (const String& path);
641661 #endif
642662 _contentType = getContentType (path);
643663#else
0 commit comments