Skip to content

Commit ceb1c26

Browse files
committed
Store response strings in PROGMEM
This saves about 1k of RAM on ESP8266 systems.
1 parent b9349dc commit ceb1c26

File tree

2 files changed

+81
-79
lines changed

2 files changed

+81
-79
lines changed

src/ESPAsyncWebServer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ class AsyncWebServerResponse {
357357
size_t _ackedLength;
358358
size_t _writtenLength;
359359
WebResponseState _state;
360-
const char* _responseCodeToString(int code);
360+
static const __FlashStringHelper* _responseCodeToString(int code);
361361

362362
public:
363363
AsyncWebServerResponse();

src/WebResponses.cpp

Lines changed: 80 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -36,49 +36,49 @@ void* memchr(void* ptr, int ch, size_t count)
3636
/*
3737
* Abstract Response
3838
* */
39-
const char* AsyncWebServerResponse::_responseCodeToString(int code) {
39+
const __FlashStringHelper* AsyncWebServerResponse::_responseCodeToString(int code) {
4040
switch (code) {
41-
case 100: return "Continue";
42-
case 101: return "Switching Protocols";
43-
case 200: return "OK";
44-
case 201: return "Created";
45-
case 202: return "Accepted";
46-
case 203: return "Non-Authoritative Information";
47-
case 204: return "No Content";
48-
case 205: return "Reset Content";
49-
case 206: return "Partial Content";
50-
case 300: return "Multiple Choices";
51-
case 301: return "Moved Permanently";
52-
case 302: return "Found";
53-
case 303: return "See Other";
54-
case 304: return "Not Modified";
55-
case 305: return "Use Proxy";
56-
case 307: return "Temporary Redirect";
57-
case 400: return "Bad Request";
58-
case 401: return "Unauthorized";
59-
case 402: return "Payment Required";
60-
case 403: return "Forbidden";
61-
case 404: return "Not Found";
62-
case 405: return "Method Not Allowed";
63-
case 406: return "Not Acceptable";
64-
case 407: return "Proxy Authentication Required";
65-
case 408: return "Request Time-out";
66-
case 409: return "Conflict";
67-
case 410: return "Gone";
68-
case 411: return "Length Required";
69-
case 412: return "Precondition Failed";
70-
case 413: return "Request Entity Too Large";
71-
case 414: return "Request-URI Too Large";
72-
case 415: return "Unsupported Media Type";
73-
case 416: return "Requested range not satisfiable";
74-
case 417: return "Expectation Failed";
75-
case 500: return "Internal Server Error";
76-
case 501: return "Not Implemented";
77-
case 502: return "Bad Gateway";
78-
case 503: return "Service Unavailable";
79-
case 504: return "Gateway Time-out";
80-
case 505: return "HTTP Version not supported";
81-
default: return "";
41+
case 100: return F("Continue");
42+
case 101: return F("Switching Protocols");
43+
case 200: return F("OK");
44+
case 201: return F("Created");
45+
case 202: return F("Accepted");
46+
case 203: return F("Non-Authoritative Information");
47+
case 204: return F("No Content");
48+
case 205: return F("Reset Content");
49+
case 206: return F("Partial Content");
50+
case 300: return F("Multiple Choices");
51+
case 301: return F("Moved Permanently");
52+
case 302: return F("Found");
53+
case 303: return F("See Other");
54+
case 304: return F("Not Modified");
55+
case 305: return F("Use Proxy");
56+
case 307: return F("Temporary Redirect");
57+
case 400: return F("Bad Request");
58+
case 401: return F("Unauthorized");
59+
case 402: return F("Payment Required");
60+
case 403: return F("Forbidden");
61+
case 404: return F("Not Found");
62+
case 405: return F("Method Not Allowed");
63+
case 406: return F("Not Acceptable");
64+
case 407: return F("Proxy Authentication Required");
65+
case 408: return F("Request Time-out");
66+
case 409: return F("Conflict");
67+
case 410: return F("Gone");
68+
case 411: return F("Length Required");
69+
case 412: return F("Precondition Failed");
70+
case 413: return F("Request Entity Too Large");
71+
case 414: return F("Request-URI Too Large");
72+
case 415: return F("Unsupported Media Type");
73+
case 416: return F("Requested range not satisfiable");
74+
case 417: return F("Expectation Failed");
75+
case 500: return F("Internal Server Error");
76+
case 501: return F("Not Implemented");
77+
case 502: return F("Bad Gateway");
78+
case 503: return F("Service Unavailable");
79+
case 504: return F("Gateway Time-out");
80+
case 505: return F("HTTP Version not supported");
81+
default: return F("");
8282
}
8383
}
8484

@@ -125,33 +125,35 @@ void AsyncWebServerResponse::addHeader(const String& name, const String& value){
125125

126126
String AsyncWebServerResponse::_assembleHead(uint8_t version){
127127
if(version){
128-
addHeader("Accept-Ranges","none");
128+
addHeader(F("Accept-Ranges"),F("none"));
129129
if(_chunked)
130-
addHeader("Transfer-Encoding","chunked");
130+
addHeader(F("Transfer-Encoding"),F("chunked"));
131131
}
132132
String out = String();
133133
int bufSize = 300;
134134
char buf[bufSize];
135135

136-
snprintf(buf, bufSize, "HTTP/1.%d %d %s\r\n", version, _code, _responseCodeToString(_code));
136+
snprintf_P(buf, bufSize, PSTR("HTTP/1.%d %d "), version, _code);
137137
out.concat(buf);
138+
out.concat(_responseCodeToString(_code));
139+
out.concat(F("\r\n"));
138140

139141
if(_sendContentLength) {
140-
snprintf(buf, bufSize, "Content-Length: %d\r\n", _contentLength);
142+
snprintf_P(buf, bufSize, PSTR("Content-Length: %d\r\n"), _contentLength);
141143
out.concat(buf);
142144
}
143145
if(_contentType.length()) {
144-
snprintf(buf, bufSize, "Content-Type: %s\r\n", _contentType.c_str());
146+
snprintf_P(buf, bufSize, PSTR("Content-Type: %s\r\n"), _contentType.c_str());
145147
out.concat(buf);
146148
}
147149

148150
for(const auto& header: _headers){
149-
snprintf(buf, bufSize, "%s: %s\r\n", header->name().c_str(), header->value().c_str());
151+
snprintf_P(buf, bufSize, PSTR("%s: %s\r\n"), header->name().c_str(), header->value().c_str());
150152
out.concat(buf);
151153
}
152154
_headers.free();
153155

154-
out.concat("\r\n");
156+
out.concat(F("\r\n"));
155157
_headLength = out.length();
156158
return out;
157159
}
@@ -254,7 +256,7 @@ AsyncAbstractResponse::AsyncAbstractResponse(AwsTemplateProcessor callback): _ca
254256
}
255257

256258
void AsyncAbstractResponse::_respond(AsyncWebServerRequest *request){
257-
addHeader("Connection","close");
259+
addHeader(F("Connection"),F("close"));
258260
_head = _assembleHead(request->version());
259261
_state = RESPONSE_HEADERS;
260262
_ack(request, 0, 0);
@@ -480,25 +482,25 @@ AsyncFileResponse::~AsyncFileResponse(){
480482
}
481483

482484
void AsyncFileResponse::_setContentType(const String& path){
483-
if (path.endsWith(".html")) _contentType = "text/html";
484-
else if (path.endsWith(".htm")) _contentType = "text/html";
485-
else if (path.endsWith(".css")) _contentType = "text/css";
486-
else if (path.endsWith(".json")) _contentType = "application/json";
487-
else if (path.endsWith(".js")) _contentType = "application/javascript";
488-
else if (path.endsWith(".png")) _contentType = "image/png";
489-
else if (path.endsWith(".gif")) _contentType = "image/gif";
490-
else if (path.endsWith(".jpg")) _contentType = "image/jpeg";
491-
else if (path.endsWith(".ico")) _contentType = "image/x-icon";
492-
else if (path.endsWith(".svg")) _contentType = "image/svg+xml";
493-
else if (path.endsWith(".eot")) _contentType = "font/eot";
494-
else if (path.endsWith(".woff")) _contentType = "font/woff";
495-
else if (path.endsWith(".woff2")) _contentType = "font/woff2";
496-
else if (path.endsWith(".ttf")) _contentType = "font/ttf";
497-
else if (path.endsWith(".xml")) _contentType = "text/xml";
498-
else if (path.endsWith(".pdf")) _contentType = "application/pdf";
499-
else if (path.endsWith(".zip")) _contentType = "application/zip";
500-
else if(path.endsWith(".gz")) _contentType = "application/x-gzip";
501-
else _contentType = "text/plain";
485+
if (path.endsWith(F(".html"))) _contentType = F("text/html");
486+
else if (path.endsWith(F(".htm"))) _contentType = F("text/html");
487+
else if (path.endsWith(F(".css"))) _contentType = F("text/css");
488+
else if (path.endsWith(F(".json"))) _contentType = F("application/json");
489+
else if (path.endsWith(F(".js"))) _contentType = F("application/javascript");
490+
else if (path.endsWith(F(".png"))) _contentType = F("image/png");
491+
else if (path.endsWith(F(".gif"))) _contentType = F("image/gif");
492+
else if (path.endsWith(F(".jpg"))) _contentType = F("image/jpeg");
493+
else if (path.endsWith(F(".ico"))) _contentType = F("image/x-icon");
494+
else if (path.endsWith(F(".svg"))) _contentType = F("image/svg+xml");
495+
else if (path.endsWith(F(".eot"))) _contentType = F("font/eot");
496+
else if (path.endsWith(F(".woff"))) _contentType = F("font/woff");
497+
else if (path.endsWith(F(".woff2"))) _contentType = F("font/woff2");
498+
else if (path.endsWith(F(".ttf"))) _contentType = F("font/ttf");
499+
else if (path.endsWith(F(".xml"))) _contentType = F("text/xml");
500+
else if (path.endsWith(F(".pdf"))) _contentType = F("application/pdf");
501+
else if (path.endsWith(F(".zip"))) _contentType = F("application/zip");
502+
else if(path.endsWith(F(".gz"))) _contentType = F("application/x-gzip");
503+
else _contentType = F("text/plain");
502504
}
503505

504506
AsyncFileResponse::AsyncFileResponse(FS &fs, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback): AsyncAbstractResponse(callback){
@@ -507,7 +509,7 @@ AsyncFileResponse::AsyncFileResponse(FS &fs, const String& path, const String& c
507509

508510
if(!download && !fs.exists(_path) && fs.exists(_path+".gz")){
509511
_path = _path+".gz";
510-
addHeader("Content-Encoding", "gzip");
512+
addHeader(F("Content-Encoding"), F("gzip"));
511513
_callback = nullptr; // Unable to process zipped templates
512514
_sendContentLength = true;
513515
_chunked = false;
@@ -527,20 +529,20 @@ AsyncFileResponse::AsyncFileResponse(FS &fs, const String& path, const String& c
527529

528530
if(download) {
529531
// set filename and force download
530-
snprintf(buf, sizeof (buf), "attachment; filename=\"%s\"", filename);
532+
snprintf_P(buf, sizeof (buf), PSTR("attachment; filename=\"%s\""), filename);
531533
} else {
532534
// force rendering
533-
snprintf(buf, sizeof (buf), "inline");
535+
snprintf_P(buf, sizeof (buf), PSTR("inline"));
534536
}
535-
addHeader("Content-Disposition", buf);
537+
addHeader(F("Content-Disposition"), buf);
536538
}
537539

538540
AsyncFileResponse::AsyncFileResponse(File content, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback): AsyncAbstractResponse(callback){
539541
_code = 200;
540542
_path = path;
541543

542-
if(!download && String(content.name()).endsWith(".gz") && !path.endsWith(".gz")){
543-
addHeader("Content-Encoding", "gzip");
544+
if(!download && String(content.name()).endsWith(F(".gz")) && !path.endsWith(F(".gz"))){
545+
addHeader(F("Content-Encoding"), F("gzip"));
544546
_callback = nullptr; // Unable to process gzipped templates
545547
_sendContentLength = true;
546548
_chunked = false;
@@ -559,11 +561,11 @@ AsyncFileResponse::AsyncFileResponse(File content, const String& path, const Str
559561
char* filename = (char*)path.c_str() + filenameStart;
560562

561563
if(download) {
562-
snprintf(buf, sizeof (buf), "attachment; filename=\"%s\"", filename);
564+
snprintf_P(buf, sizeof (buf), PSTR("attachment; filename=\"%s\""), filename);
563565
} else {
564-
snprintf(buf, sizeof (buf), "inline");
566+
snprintf_P(buf, sizeof (buf), PSTR("inline"));
565567
}
566-
addHeader("Content-Disposition", buf);
568+
addHeader(F("Content-Disposition"), buf);
567569
}
568570

569571
size_t AsyncFileResponse::_fillBuffer(uint8_t *data, size_t len){

0 commit comments

Comments
 (0)