1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-08-26 01:44:17 +03:00

Improvements to the existing ETag implementation (#8227)

* WebServer eTag implementation improvements
This commit is contained in:
Matthias Hertel
2021-09-29 11:58:40 +02:00
committed by GitHub
parent 193043d19b
commit 3f4bcbe483
10 changed files with 708 additions and 15 deletions

View File

@@ -9,6 +9,26 @@
namespace esp8266webserver {
// calculate an ETag for a file in filesystem based on md5 checksum
// that can be used in the http headers - include quotes.
static String calcETag(FS &fs, const String &path) {
String result;
// calculate eTag using md5 checksum
uint8_t md5_buf[16];
File f = fs.open(path, "r");
MD5Builder calcMD5;
calcMD5.begin();
calcMD5.addStream(f, f.size());
calcMD5.calculate();
calcMD5.getBytes(md5_buf);
f.close();
// create a minimal-length eTag using base64 byte[]->text encoding.
result = "\"" + base64::encode(md5_buf, 16, false) + "\"";
return(result);
} // calcETag
template<typename ServerType>
class FunctionRequestHandler : public RequestHandler<ServerType> {
using WebServerType = ESP8266WebServerTemplate<ServerType>;
@@ -92,6 +112,7 @@ protected:
};
// serve all files within a given directory
template<typename ServerType>
class StaticDirectoryRequestHandler : public StaticRequestHandler<ServerType> {
@@ -117,6 +138,7 @@ public:
DEBUGV("DirectoryRequestHandler::handle: request=%s _uri=%s\r\n", requestUri.c_str(), SRH::_uri.c_str());
String path;
String eTagCode;
path.reserve(SRH::_path.length() + requestUri.length() + 32);
path = SRH::_path;
@@ -156,10 +178,28 @@ public:
return false;
}
if (server._eTagEnabled) {
if (server._eTagFunction) {
eTagCode = (server._eTagFunction)(SRH::_fs, path);
} else {
eTagCode = esp8266webserver::calcETag(SRH::_fs, path);
}
if (server.header("If-None-Match") == eTagCode) {
server.send(304);
return true;
}
}
if (SRH::_cache_header.length() != 0)
server.sendHeader("Cache-Control", SRH::_cache_header);
if ((server._eTagEnabled) && (eTagCode.length() > 0)) {
server.sendHeader("ETag", eTagCode);
}
server.streamFile(f, contentType, requestMethod);
return true;
}
@@ -167,6 +207,8 @@ protected:
size_t _baseUriLength;
};
// Serve a specific, single file
template<typename ServerType>
class StaticFileRequestHandler
:
@@ -180,13 +222,6 @@ public:
:
StaticRequestHandler<ServerType>{fs, path, uri, cache_header}
{
File f = SRH::_fs.open(path, "r");
MD5Builder calcMD5;
calcMD5.begin();
calcMD5.addStream(f, f.size());
calcMD5.calculate();
calcMD5.getBytes(_ETag_md5);
f.close();
}
bool canHandle(HTTPMethod requestMethod, const String& requestUri) override {
@@ -197,11 +232,17 @@ public:
if (!canHandle(requestMethod, requestUri))
return false;
const String etag = "\"" + base64::encode(_ETag_md5, 16, false) + "\"";
if (server._eTagEnabled) {
if (server._eTagFunction) {
_eTagCode = (server._eTagFunction)(SRH::_fs, SRH::_path);
} else if (_eTagCode.isEmpty()) {
_eTagCode = esp8266webserver::calcETag(SRH::_fs, SRH::_path);
}
if(server.header("If-None-Match") == etag){
server.send(304);
return true;
if (server.header("If-None-Match") == _eTagCode) {
server.send(304);
return true;
}
}
File f = SRH::_fs.open(SRH::_path, "r");
@@ -217,14 +258,16 @@ public:
if (SRH::_cache_header.length() != 0)
server.sendHeader("Cache-Control", SRH::_cache_header);
server.sendHeader("ETag", etag);
if ((server._eTagEnabled) && (_eTagCode.length() > 0)) {
server.sendHeader("ETag", _eTagCode);
}
server.streamFile(f, mime::getContentType(SRH::_path), requestMethod);
return true;
}
protected:
uint8_t _ETag_md5[16];
String _eTagCode; // ETag code calculated for this file as used in http header include quotes.
};
} // namespace