@@ -125,9 +125,8 @@ const char* AsyncWebServerResponse::responseCodeToString(int code) {
125
125
return T_HTTP_CODE_ANY;
126
126
}
127
127
}
128
- #else // ESP8266
129
- const __FlashStringHelper* AsyncWebServerResponse::responseCodeToString (int code)
130
- {
128
+ #else // ESP8266
129
+ const __FlashStringHelper* AsyncWebServerResponse::responseCodeToString (int code) {
131
130
switch (code) {
132
131
case 100 :
133
132
return FPSTR (T_HTTP_CODE_100);
@@ -230,12 +229,12 @@ void AsyncWebServerResponse::setCode(int code) {
230
229
}
231
230
232
231
void AsyncWebServerResponse::setContentLength (size_t len) {
233
- if (_state == RESPONSE_SETUP)
232
+ if (_state == RESPONSE_SETUP && addHeader (T_Content_Length, len, true ) )
234
233
_contentLength = len;
235
234
}
236
235
237
236
void AsyncWebServerResponse::setContentType (const char * type) {
238
- if (_state == RESPONSE_SETUP)
237
+ if (_state == RESPONSE_SETUP && addHeader (T_Content_Type, type, true ) )
239
238
_contentType = type;
240
239
}
241
240
@@ -249,6 +248,11 @@ bool AsyncWebServerResponse::removeHeader(const char* name) {
249
248
return false ;
250
249
}
251
250
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
+
252
256
bool AsyncWebServerResponse::addHeader (const char * name, const char * value, bool replaceExisting) {
253
257
for (auto i = _headers.begin (); i != _headers.end (); ++i) {
254
258
if (i->name ().equalsIgnoreCase (name)) {
@@ -268,41 +272,56 @@ bool AsyncWebServerResponse::addHeader(const char* name, const char* value, bool
268
272
return true ;
269
273
}
270
274
271
- String AsyncWebServerResponse::_assembleHead (uint8_t version) {
275
+ void AsyncWebServerResponse::_assembleHead (String& buffer, uint8_t version) {
272
276
if (version) {
273
277
addHeader (T_Accept_Ranges, T_none, false );
274
278
if (_chunked)
275
279
addHeader (T_Transfer_Encoding, T_chunked, false );
276
280
}
277
- String out;
278
- constexpr size_t bufSize = 300 ;
279
- char buf[bufSize];
280
281
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 );
287
284
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 ;
296
293
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
297
311
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);
300
320
}
301
321
_headers.clear ();
302
322
303
- out.concat (T_rn);
304
- _headLength = out.length ();
305
- return out;
323
+ buffer.concat (T_rn);
324
+ _headLength = buffer.length ();
306
325
}
307
326
308
327
bool AsyncWebServerResponse::_started () const { return _state > RESPONSE_SETUP; }
@@ -337,7 +356,8 @@ AsyncBasicResponse::AsyncBasicResponse(int code, const char* contentType, const
337
356
338
357
void AsyncBasicResponse::_respond (AsyncWebServerRequest* request) {
339
358
_state = RESPONSE_HEADERS;
340
- String out = _assembleHead (request->version ());
359
+ String out;
360
+ _assembleHead (out, request->version ());
341
361
size_t outLen = out.length ();
342
362
size_t space = request->client ()->space ();
343
363
if (!_contentLength && space >= outLen) {
@@ -411,7 +431,7 @@ AsyncAbstractResponse::AsyncAbstractResponse(AwsTemplateProcessor callback) : _c
411
431
412
432
void AsyncAbstractResponse::_respond (AsyncWebServerRequest* request) {
413
433
addHeader (T_Connection, T_close, false );
414
- _head = _assembleHead (request->version ());
434
+ _assembleHead (_head, request->version ());
415
435
_state = RESPONSE_HEADERS;
416
436
_ack (request, 0 , 0 );
417
437
}
@@ -635,9 +655,9 @@ AsyncFileResponse::~AsyncFileResponse() {
635
655
void AsyncFileResponse::_setContentTypeFromPath (const String& path) {
636
656
#if HAVE_EXTERN_GET_Content_Type_FUNCTION
637
657
#ifndef ESP8266
638
- extern const char * getContentType (const String& path);
658
+ extern const char * getContentType (const String& path);
639
659
#else
640
- extern const __FlashStringHelper* getContentType (const String& path);
660
+ extern const __FlashStringHelper* getContentType (const String& path);
641
661
#endif
642
662
_contentType = getContentType (path);
643
663
#else
0 commit comments