PsychichHTTP v2-dev

This commit is contained in:
iranl
2024-12-30 14:37:09 +01:00
parent 2cf5201285
commit 78459c2d08
118 changed files with 5453 additions and 4972 deletions

View File

@@ -5,70 +5,88 @@
/*************************************/
PsychicStaticFileHandler::PsychicStaticFileHandler(const char* uri, FS& fs, const char* path, const char* cache_control)
: _fs(fs), _uri(uri), _path(path), _default_file("index.html"), _cache_control(cache_control), _last_modified("")
: _fs(fs), _uri(uri), _path(path), _default_file("index.html"), _cache_control(cache_control), _last_modified("")
{
// Ensure leading '/'
if (_uri.length() == 0 || _uri[0] != '/') _uri = "/" + _uri;
if (_path.length() == 0 || _path[0] != '/') _path = "/" + _path;
if (_uri.length() == 0 || _uri[0] != '/')
_uri = "/" + _uri;
if (_path.length() == 0 || _path[0] != '/')
_path = "/" + _path;
// If path ends with '/' we assume a hint that this is a directory to improve performance.
// However - if it does not end with '/' we, can't assume a file, path can still be a directory.
_isDir = _path[_path.length()-1] == '/';
_isDir = _path[_path.length() - 1] == '/';
// Remove the trailing '/' so we can handle default file
// Notice that root will be "" not "/"
if (_uri[_uri.length()-1] == '/') _uri = _uri.substring(0, _uri.length()-1);
if (_path[_path.length()-1] == '/') _path = _path.substring(0, _path.length()-1);
if (_uri[_uri.length() - 1] == '/')
_uri = _uri.substring(0, _uri.length() - 1);
if (_path[_path.length() - 1] == '/')
_path = _path.substring(0, _path.length() - 1);
// Reset stats
_gzipFirst = false;
_gzipStats = 0xF8;
}
PsychicStaticFileHandler& PsychicStaticFileHandler::setIsDir(bool isDir){
_isDir = isDir;
return *this;
}
PsychicStaticFileHandler& PsychicStaticFileHandler::setDefaultFile(const char* filename){
_default_file = String(filename);
return *this;
}
PsychicStaticFileHandler& PsychicStaticFileHandler::setCacheControl(const char* cache_control){
_cache_control = String(cache_control);
return *this;
}
PsychicStaticFileHandler& PsychicStaticFileHandler::setLastModified(const char* last_modified){
_last_modified = String(last_modified);
return *this;
}
PsychicStaticFileHandler& PsychicStaticFileHandler::setLastModified(struct tm* last_modified){
char result[30];
strftime (result,30,"%a, %d %b %Y %H:%M:%S %Z", last_modified);
return setLastModified((const char *)result);
}
bool PsychicStaticFileHandler::canHandle(PsychicRequest *request)
PsychicStaticFileHandler* PsychicStaticFileHandler::setIsDir(bool isDir)
{
if(request->method() != HTTP_GET || !request->uri().startsWith(_uri) )
_isDir = isDir;
return this;
}
PsychicStaticFileHandler* PsychicStaticFileHandler::setDefaultFile(const char* filename)
{
_default_file = filename;
return this;
}
PsychicStaticFileHandler* PsychicStaticFileHandler::setCacheControl(const char* cache_control)
{
_cache_control = cache_control;
return this;
}
PsychicStaticFileHandler* PsychicStaticFileHandler::setLastModified(const char* last_modified)
{
_last_modified = String(last_modified);
return this;
}
PsychicStaticFileHandler* PsychicStaticFileHandler::setLastModified(struct tm* last_modified)
{
char result[30];
strftime(result, 30, "%a, %d %b %Y %H:%M:%S %Z", last_modified);
return setLastModified((const char*)result);
}
bool PsychicStaticFileHandler::canHandle(PsychicRequest* request)
{
if (request->method() != HTTP_GET) {
ESP_LOGD(PH_TAG, "Request %s refused by PsychicStaticFileHandler: %s", request->uri().c_str(), request->methodStr().c_str());
return false;
}
if (_getFile(request))
if (!request->uri().startsWith(_uri)) {
ESP_LOGD(PH_TAG, "Request %s refused by PsychicStaticFileHandler: does not start with %s", request->uri().c_str(), _uri.c_str());
return false;
}
if (_getFile(request)) {
return true;
}
ESP_LOGD(PH_TAG, "Request %s refused by PsychicStaticFileHandler: file not found", request->uri().c_str());
return false;
}
bool PsychicStaticFileHandler::_getFile(PsychicRequest *request)
bool PsychicStaticFileHandler::_getFile(PsychicRequest* request)
{
// Remove the found uri
String path = request->uri().substring(_uri.length());
// We can skip the file check and look for default if request is to the root of a directory or that request path ends with '/'
bool canSkipFileCheck = (_isDir && path.length() == 0) || (path.length() && path[path.length()-1] == '/');
bool canSkipFileCheck = (_isDir && path.length() == 0) || (path.length() && path[path.length() - 1] == '/');
path = _path + path;
@@ -81,7 +99,7 @@ bool PsychicStaticFileHandler::_getFile(PsychicRequest *request)
return false;
// Try to add default file, ensure there is a trailing '/' ot the path.
if (path.length() == 0 || path[path.length()-1] != '/')
if (path.length() == 0 || path[path.length() - 1] != '/')
path += "/";
path += _default_file;
@@ -100,14 +118,14 @@ bool PsychicStaticFileHandler::_fileExists(const String& path)
if (_gzipFirst) {
_file = _fs.open(gzip, "r");
gzipFound = FILE_IS_REAL(_file);
if (!gzipFound){
if (!gzipFound) {
_file = _fs.open(path, "r");
fileFound = FILE_IS_REAL(_file);
}
} else {
_file = _fs.open(path, "r");
fileFound = FILE_IS_REAL(_file);
if (!fileFound){
if (!fileFound) {
_file = _fs.open(gzip, "r");
gzipFound = FILE_IS_REAL(_file);
}
@@ -115,17 +133,21 @@ bool PsychicStaticFileHandler::_fileExists(const String& path)
bool found = fileFound || gzipFound;
if (found)
{
if (found) {
_filename = path;
// Calculate gzip statistic
_gzipStats = (_gzipStats << 1) + (gzipFound ? 1 : 0);
if (_gzipStats == 0x00) _gzipFirst = false; // All files are not gzip
else if (_gzipStats == 0xFF) _gzipFirst = true; // All files are gzip
else _gzipFirst = _countBits(_gzipStats) > 4; // IF we have more gzip files - try gzip first
if (_gzipStats == 0x00)
_gzipFirst = false; // All files are not gzip
else if (_gzipStats == 0xFF)
_gzipFirst = true; // All files are gzip
else
_gzipFirst = _countBits(_gzipStats) > 4; // IF we have more gzip files - try gzip first
}
ESP_LOGD(PH_TAG, "PsychicStaticFileHandler _fileExists(%s): %d", path.c_str(), found);
return found;
}
@@ -133,36 +155,32 @@ uint8_t PsychicStaticFileHandler::_countBits(const uint8_t value) const
{
uint8_t w = value;
uint8_t n;
for (n=0; w!=0; n++) w&=w-1;
for (n = 0; w != 0; n++)
w &= w - 1;
return n;
}
esp_err_t PsychicStaticFileHandler::handleRequest(PsychicRequest *request)
esp_err_t PsychicStaticFileHandler::handleRequest(PsychicRequest* request, PsychicResponse* res)
{
if (_file == true)
{
//is it not modified?
if (_file == true) {
// is it not modified?
String etag = String(_file.size());
if (_last_modified.length() && _last_modified == request->header("If-Modified-Since"))
{
if (_last_modified.length() && _last_modified == request->header("If-Modified-Since")) {
_file.close();
request->reply(304); // Not modified
res->send(304); // Not modified
}
//does our Etag match?
else if (_cache_control.length() && request->hasHeader("If-None-Match") && request->header("If-None-Match").equals(etag))
{
// does our Etag match?
else if (_cache_control.length() && request->hasHeader("If-None-Match") && request->header("If-None-Match").equals(etag)) {
_file.close();
PsychicResponse response(request);
response.addHeader("Cache-Control", _cache_control.c_str());
response.addHeader("ETag", etag.c_str());
response.setCode(304);
response.send();
res->addHeader("Cache-Control", _cache_control.c_str());
res->addHeader("ETag", etag.c_str());
res->setCode(304);
res->send();
}
//nope, send them the full file.
else
{
PsychicFileResponse response(request, _fs, _filename);
// nope, send them the full file.
else {
PsychicFileResponse response(res, _fs, _filename);
if (_last_modified.length())
response.addHeader("Last-Modified", _last_modified.c_str());
@@ -174,7 +192,7 @@ esp_err_t PsychicStaticFileHandler::handleRequest(PsychicRequest *request)
return response.send();
}
} else {
return request->reply(404);
return res->send(404);
}
return ESP_OK;