mirror of
https://github.com/me-no-dev/ESPAsyncWebServer.git
synced 2025-07-29 18:27:34 +02:00
rework INM/IMS handling for AsyncStaticWebHandler
IMS template must contain GMT timezone, not local - "%a, %d %b %Y %H:%M:%S GMT" create etag based on timestamp + filesize INM header handling should have precedence over IMS
This commit is contained in:
@ -57,12 +57,19 @@ class AsyncStaticWebHandler : public AsyncWebHandler {
|
||||
AsyncStaticWebHandler& setIsDir(bool isDir);
|
||||
AsyncStaticWebHandler& setDefaultFile(const char* filename);
|
||||
AsyncStaticWebHandler& setCacheControl(const char* cache_control);
|
||||
|
||||
/**
|
||||
* @brief Set the Last-Modified time for the object
|
||||
*
|
||||
* @param last_modified
|
||||
* @return AsyncStaticWebHandler&
|
||||
*/
|
||||
AsyncStaticWebHandler& setLastModified(const char* last_modified);
|
||||
AsyncStaticWebHandler& setLastModified(struct tm* last_modified);
|
||||
#ifdef ESP8266
|
||||
AsyncStaticWebHandler& setLastModified(time_t last_modified);
|
||||
AsyncStaticWebHandler& setLastModified(); // sets to current time. Make sure sntp is runing and time is updated
|
||||
#endif
|
||||
// sets to current time. Make sure sntp is runing and time is updated
|
||||
AsyncStaticWebHandler& setLastModified();
|
||||
|
||||
AsyncStaticWebHandler& setTemplateProcessor(AwsTemplateProcessor newCallback);
|
||||
};
|
||||
|
||||
|
@ -70,12 +70,12 @@ AsyncStaticWebHandler& AsyncStaticWebHandler::setIsDir(bool isDir) {
|
||||
}
|
||||
|
||||
AsyncStaticWebHandler& AsyncStaticWebHandler::setDefaultFile(const char* filename) {
|
||||
_default_file = String(filename);
|
||||
_default_file = filename;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AsyncStaticWebHandler& AsyncStaticWebHandler::setCacheControl(const char* cache_control) {
|
||||
_cache_control = String(cache_control);
|
||||
_cache_control = cache_control;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -85,16 +85,20 @@ AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(const char* last_m
|
||||
}
|
||||
|
||||
AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(struct tm* last_modified) {
|
||||
auto formatP = PSTR("%a, %d %b %Y %H:%M:%S %Z");
|
||||
char result[30];
|
||||
#ifdef ESP8266
|
||||
auto formatP = PSTR("%a, %d %b %Y %H:%M:%S GMT");
|
||||
char format[strlen_P(formatP) + 1];
|
||||
strcpy_P(format, formatP);
|
||||
#else
|
||||
static constexpr const char* format = "%a, %d %b %Y %H:%M:%S GMT";
|
||||
#endif
|
||||
|
||||
char result[30];
|
||||
strftime(result, sizeof(result), format, last_modified);
|
||||
return setLastModified((const char*)result);
|
||||
_last_modified = result;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef ESP8266
|
||||
AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(time_t last_modified) {
|
||||
return setLastModified((struct tm*)gmtime(&last_modified));
|
||||
}
|
||||
@ -105,7 +109,7 @@ AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified() {
|
||||
return *this;
|
||||
return setLastModified(last_modified);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool AsyncStaticWebHandler::canHandle(AsyncWebServerRequest* request) const {
|
||||
return request->isHTTP() && request->method() == HTTP_GET && request->url().startsWith(_uri) && _getFile(request);
|
||||
}
|
||||
@ -194,50 +198,59 @@ uint8_t AsyncStaticWebHandler::_countBits(const uint8_t value) const {
|
||||
|
||||
void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest* request) {
|
||||
// Get the filename from request->_tempObject and free it
|
||||
String filename = String((char*)request->_tempObject);
|
||||
String filename((char*)request->_tempObject);
|
||||
free(request->_tempObject);
|
||||
request->_tempObject = NULL;
|
||||
|
||||
if (request->_tempFile == true) {
|
||||
if (request->_tempFile != true){
|
||||
request->send(404);
|
||||
return;
|
||||
}
|
||||
|
||||
time_t lw = request->_tempFile.getLastWrite(); // get last file mod time (if supported by FS)
|
||||
// set etag to lastmod timestamp if available, otherwise to size
|
||||
String etag;
|
||||
if (lw) {
|
||||
setLastModified(gmtime(&lw));
|
||||
setLastModified(lw);
|
||||
#if defined(TARGET_RP2040)
|
||||
// time_t == long long int
|
||||
const size_t len = 1 + 8 * sizeof(time_t);
|
||||
constexpr size_t len = 1 + 8 * sizeof(time_t);
|
||||
char buf[len];
|
||||
char* ret = lltoa(lw, buf, len, 10);
|
||||
char* ret = lltoa(lw ^ request->_tempFile.size(), buf, len, 10);
|
||||
etag = ret ? String(ret) : String(request->_tempFile.size());
|
||||
#else
|
||||
etag = String(lw);
|
||||
etag = lw ^ request->_tempFile.size(); // etag combines file size and lastmod timestamp
|
||||
#endif
|
||||
} else {
|
||||
etag = String(request->_tempFile.size());
|
||||
etag = request->_tempFile.size();
|
||||
}
|
||||
if (_last_modified.length() && _last_modified == request->header(T_IMS)) {
|
||||
|
||||
bool not_modified = false;
|
||||
|
||||
// if-none-match has precedence over if-modified-since
|
||||
if (request->hasHeader(T_INM))
|
||||
not_modified = request->header(T_INM).equals(etag);
|
||||
else if (_last_modified.length())
|
||||
not_modified = request->header(T_IMS).equals(_last_modified);
|
||||
|
||||
AsyncWebServerResponse* response;
|
||||
|
||||
if (not_modified){
|
||||
request->_tempFile.close();
|
||||
request->send(304); // Not modified
|
||||
} else if (_cache_control.length() && request->hasHeader(T_INM) && request->header(T_INM).equals(etag)) {
|
||||
request->_tempFile.close();
|
||||
AsyncWebServerResponse* response = new AsyncBasicResponse(304); // Not modified
|
||||
response->addHeader(T_Cache_Control, _cache_control.c_str());
|
||||
response->addHeader(T_ETag, etag.c_str());
|
||||
request->send(response);
|
||||
response = new AsyncBasicResponse(304); // Not modified
|
||||
} else {
|
||||
AsyncWebServerResponse* response = new AsyncFileResponse(request->_tempFile, filename, String(), false, _callback);
|
||||
if (_last_modified.length())
|
||||
response->addHeader(T_Last_Modified, _last_modified.c_str());
|
||||
if (_cache_control.length()) {
|
||||
response->addHeader(T_Cache_Control, _cache_control.c_str());
|
||||
response->addHeader(T_ETag, etag.c_str());
|
||||
}
|
||||
request->send(response);
|
||||
response = new AsyncFileResponse(request->_tempFile, filename, emptyString, false, _callback);
|
||||
}
|
||||
} else {
|
||||
request->send(404);
|
||||
}
|
||||
|
||||
response->addHeader(T_ETag, etag.c_str());
|
||||
|
||||
if (_last_modified.length())
|
||||
response->addHeader(T_Last_Modified, _last_modified.c_str());
|
||||
if (_cache_control.length())
|
||||
response->addHeader(T_Cache_Control, _cache_control.c_str());
|
||||
|
||||
request->send(response);
|
||||
|
||||
}
|
||||
|
||||
AsyncStaticWebHandler& AsyncStaticWebHandler::setTemplateProcessor(AwsTemplateProcessor newCallback) {
|
||||
|
Reference in New Issue
Block a user