From 69b5a6b0f9149cf44530b87e6fc60cb302fb3015 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Mon, 18 May 2020 18:10:31 +0200 Subject: [PATCH] Flash size reduction for mime-type * moving to 2 arrays for suffix and mime-type, with PROGMEM strings * adding `#define MIMETYPE_MINIMAL` to reduce the footprint to mime-types that are strictly necessary --- .../src/ESP8266WebServer-impl.h | 12 +- libraries/ESP8266WebServer/src/Parsing-impl.h | 4 +- .../src/detail/RequestHandlersImpl.h | 6 +- .../ESP8266WebServer/src/detail/mimetable.cpp | 145 +++++++++++++----- .../ESP8266WebServer/src/detail/mimetable.h | 15 +- 5 files changed, 127 insertions(+), 55 deletions(-) diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h index f085a8afe6..d627c193f6 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h @@ -259,7 +259,7 @@ void ESP8266WebServerTemplate::requestAuthentication(HTTPAuthMethod sendHeader(String(FPSTR(WWW_Authenticate)), String(F("Digest realm=\"")) +_srealm + String(F("\", qop=\"auth\", nonce=\"")) + _snonce + String(F("\", opaque=\"")) + _sopaque + String('\"')); } using namespace mime; - send(401, String(FPSTR(mimeTable[html].mimeType)), authFailMsg); + send(401, String(FPSTR(mimeTable[html])), authFailMsg); } template @@ -408,7 +408,7 @@ void ESP8266WebServerTemplate::_prepareHeader(String& response, int using namespace mime; if (!content_type) - content_type = mimeTable[html].mimeType; + content_type = mimeTable[html]; sendHeader(String(F("Content-Type")), String(FPSTR(content_type)), true); if (_contentLength == CONTENT_LENGTH_NOT_SET) { @@ -536,9 +536,9 @@ void ESP8266WebServerTemplate::_streamFileCore(const size_t fileSize { using namespace mime; setContentLength(fileSize); - if (fileName.endsWith(String(FPSTR(mimeTable[gz].endsWith))) && - contentType != String(FPSTR(mimeTable[gz].mimeType)) && - contentType != String(FPSTR(mimeTable[none].mimeType))) { + if (fileName.endsWith(String(FPSTR(mimeTableSuffix[gz]))) && + contentType != String(FPSTR(mimeTable[gz])) && + contentType != String(FPSTR(mimeTable[none]))) { sendHeader(F("Content-Encoding"), F("gzip")); } send(200, contentType, emptyString); @@ -683,7 +683,7 @@ void ESP8266WebServerTemplate::_handleRequest() { } if (!handled) { using namespace mime; - send(404, String(FPSTR(mimeTable[html].mimeType)), String(F("Not found: ")) + _currentUri); + send(404, String(FPSTR(mimeTable[html])), String(F("Not found: ")) + _currentUri); handled = true; } if (handled) { diff --git a/libraries/ESP8266WebServer/src/Parsing-impl.h b/libraries/ESP8266WebServer/src/Parsing-impl.h index 54bcd6c28e..0c8c81e92b 100644 --- a/libraries/ESP8266WebServer/src/Parsing-impl.h +++ b/libraries/ESP8266WebServer/src/Parsing-impl.h @@ -163,7 +163,7 @@ bool ESP8266WebServerTemplate::_parseRequest(ClientType& client) { if (headerName.equalsIgnoreCase(FPSTR(Content_Type))){ using namespace mime; - if (headerValue.startsWith(FPSTR(mimeTable[txt].mimeType))){ + if (headerValue.startsWith(FPSTR(mimeTable[txt]))){ isForm = false; } else if (headerValue.startsWith(F("application/x-www-form-urlencoded"))){ isForm = false; @@ -434,7 +434,7 @@ bool ESP8266WebServerTemplate::_parseForm(ClientType& client, const DEBUG_OUTPUT.println(argName); #endif using namespace mime; - argType = FPSTR(mimeTable[txt].mimeType); + argType = FPSTR(mimeTable[txt]); line = client.readStringUntil('\r'); client.readStringUntil('\n'); if (line.length() > 12 && line.substring(0, 12).equalsIgnoreCase(FPSTR(Content_Type))){ diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h index fb452af48c..f7c186eca4 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h @@ -124,10 +124,10 @@ class StaticRequestHandler : public RequestHandler { // look for gz file, only if the original specified path is not a gz. So part only works to send gzip via content encoding when a non compressed is asked for // if you point the the path to gzip you will serve the gzip as content type "application/x-gzip", not text or javascript etc... - if (!path.endsWith(FPSTR(mimeTable[gz].endsWith)) && !_fs.exists(path)) { - String pathWithGz = path + FPSTR(mimeTable[gz].endsWith); + if (!path.endsWith(FPSTR(mimeTableSuffix[gz])) && !_fs.exists(path)) { + String pathWithGz = path + FPSTR(mimeTableSuffix[gz]); if(_fs.exists(pathWithGz)) - path += FPSTR(mimeTable[gz].endsWith); + path += FPSTR(mimeTableSuffix[gz]); } File f = _fs.open(path, "r"); diff --git a/libraries/ESP8266WebServer/src/detail/mimetable.cpp b/libraries/ESP8266WebServer/src/detail/mimetable.cpp index c4a20cc0e1..585746dad3 100644 --- a/libraries/ESP8266WebServer/src/detail/mimetable.cpp +++ b/libraries/ESP8266WebServer/src/detail/mimetable.cpp @@ -5,48 +5,123 @@ namespace mime { -// Table of extension->MIME strings stored in PROGMEM, needs to be global due to GCC section typing rules -const Entry mimeTable[maxType] PROGMEM = +static const char kHtmlSuffix[] PROGMEM = ".html"; +static const char kHtmSuffix[] PROGMEM = ".htm"; +static const char kCssSuffix[] PROGMEM = ".css"; +static const char kTxtSuffix[] PROGMEM = ".txt"; +static const char kJsSuffix[] PROGMEM = ".js"; +static const char kJsonSuffix[] PROGMEM = ".json"; +static const char kPngSuffix[] PROGMEM = ".png"; +static const char kGifSuffix[] PROGMEM = ".gif"; +static const char kJpgSuffix[] PROGMEM = ".jpg"; +static const char kJpegSuffix[] PROGMEM = ".jpeg"; +static const char kIcoSuffix[] PROGMEM = ".ico"; +static const char kSvgSuffix[] PROGMEM = ".svg"; +static const char kTtfSuffix[] PROGMEM = ".ttf"; +static const char kOtfSuffix[] PROGMEM = ".otf"; +static const char kWoffSuffix[] PROGMEM = ".woff"; +static const char kWoff2Suffix[] PROGMEM = ".woff2"; +static const char kEotSuffix[] PROGMEM = ".eot"; +static const char kSfntSuffix[] PROGMEM = ".sfnt"; +static const char kXmlSuffix[] PROGMEM = ".xml"; +static const char kPdfSuffix[] PROGMEM = ".pdf"; +static const char kZipSuffix[] PROGMEM = ".zip"; +static const char kGzSuffix[] PROGMEM = ".gz"; +static const char kAppcacheSuffix[] PROGMEM = ".appcache"; +static const char kDefaultSuffix[] PROGMEM = ""; + +const char * mimeTableSuffix[maxType] PROGMEM = +{ + kHtmlSuffix, + kHtmSuffix, + kTxtSuffix, +#ifndef MIMETYPE_MINIMAL + kCssSuffix, + kJsSuffix, + kJsonSuffix, + kPngSuffix, + kGifSuffix, + kJpgSuffix, + kJpegSuffix, + kIcoSuffix, + kSvgSuffix, + kTtfSuffix, + kOtfSuffix, + kWoffSuffix, + kWoff2Suffix, + kEotSuffix, + kSfntSuffix, + kXmlSuffix, + kPdfSuffix, + kZipSuffix, + kAppcacheSuffix, +#endif // MIMETYPE_MINIMAL + kGzSuffix, + kDefaultSuffix +}; + +static const char kHtml[] PROGMEM = "text/html"; +static const char kCss[] PROGMEM = "text/css"; +static const char kTxt[] PROGMEM = "text/plain"; +static const char kJs[] PROGMEM = "application/javascript"; +static const char kJson[] PROGMEM = "application/json"; +static const char kPng[] PROGMEM = "image/png"; +static const char kGif[] PROGMEM = "image/gif"; +static const char kJpg[] PROGMEM = "image/jpeg"; +static const char kJpeg[] PROGMEM = "image/jpeg"; +static const char kIco[] PROGMEM = "image/x-icon"; +static const char kSvg[] PROGMEM = "image/svg+xml"; +static const char kTtf[] PROGMEM = "application/x-font-ttf"; +static const char kOtf[] PROGMEM = "application/x-font-opentype"; +static const char kWoff[] PROGMEM = "application/font-woff"; +static const char kWoff2[] PROGMEM = "application/font-woff2"; +static const char kEot[] PROGMEM = "application/vnd.ms-fontobject"; +static const char kSfnt[] PROGMEM = "application/font-sfnt"; +static const char kXml[] PROGMEM = "text/xml"; +static const char kPdf[] PROGMEM = "application/pdf"; +static const char kZip[] PROGMEM = "application/zip"; +static const char kGz[] PROGMEM = "application/x-gzip"; +static const char kAppcache[] PROGMEM = "text/cache-manifest"; +static const char kDefault[] PROGMEM = "application/octet-stream"; + +const char * mimeTable[maxType] PROGMEM = { - { ".html", "text/html" }, - { ".htm", "text/html" }, - { ".css", "text/css" }, - { ".txt", "text/plain" }, - { ".js", "application/javascript" }, - { ".json", "application/json" }, - { ".png", "image/png" }, - { ".gif", "image/gif" }, - { ".jpg", "image/jpeg" }, - { ".jpeg", "image/jpeg" }, - { ".ico", "image/x-icon" }, - { ".svg", "image/svg+xml" }, - { ".ttf", "application/x-font-ttf" }, - { ".otf", "application/x-font-opentype" }, - { ".woff", "application/font-woff" }, - { ".woff2", "application/font-woff2" }, - { ".eot", "application/vnd.ms-fontobject" }, - { ".sfnt", "application/font-sfnt" }, - { ".xml", "text/xml" }, - { ".pdf", "application/pdf" }, - { ".zip", "application/zip" }, - { ".gz", "application/x-gzip" }, - { ".appcache", "text/cache-manifest" }, - { "", "application/octet-stream" } + kHtml, + kHtml, + kTxt, +#ifndef MIMETYPE_MINIMAL + kCss, + kJs, + kJson, + kPng, + kGif, + kJpg, + kJpeg, + kIco, + kSvg, + kTtf, + kOtf, + kWoff, + kWoff2, + kEot, + kSfnt, + kXml, + kPdf, + kZip, + kAppcache, +#endif // MIMETYPE_MINIMAL + kGz, + kDefault }; String getContentType(const String& path) { - char buff[sizeof(mimeTable[0].mimeType)]; - // Check all entries but last one for match, return if found - for (size_t i=0; i < sizeof(mimeTable)/sizeof(mimeTable[0])-1; i++) { - strcpy_P(buff, mimeTable[i].endsWith); - if (path.endsWith(buff)) { - strcpy_P(buff, mimeTable[i].mimeType); - return String(buff); + for (size_t i = 0; i < maxType; i++) { + if (path.endsWith(FPSTR(mimeTableSuffix[i]))) { + return String(FPSTR(mimeTable[i])); } } // Fall-through and just return default type - strcpy_P(buff, mimeTable[sizeof(mimeTable)/sizeof(mimeTable[0])-1].mimeType); - return String(buff); + return String(FPSTR(kDefault)); } } diff --git a/libraries/ESP8266WebServer/src/detail/mimetable.h b/libraries/ESP8266WebServer/src/detail/mimetable.h index 6e6a4e9631..684d39f576 100644 --- a/libraries/ESP8266WebServer/src/detail/mimetable.h +++ b/libraries/ESP8266WebServer/src/detail/mimetable.h @@ -10,8 +10,9 @@ enum type { html, htm, - css, txt, +#ifndef MIMETYPE_MINIMAL // allow to compile with only the strict minimum of mime-types + css, js, json, png, @@ -29,20 +30,16 @@ enum type xml, pdf, zip, - gz, appcache, +#endif // MIMETYPE_MINIMAL + gz, none, maxType }; -struct Entry -{ - const char endsWith[16]; - const char mimeType[32]; -}; - -extern const Entry mimeTable[maxType]; +extern const char * mimeTableSuffix[maxType]; +extern const char * mimeTable[maxType]; String getContentType(const String& path); }