This handler will serve a 302 response to a client request for a SP… (#36)
* This handler will serve a 302 response to a client request for a SPIFFS file if the request comes from the STA side of the ESP network. If the request comes from the AP side then it serves the file from SPIFFS. * corrections. plus readme * Update README.md extra space * move wifi to cpp
This commit is contained in:
parent
bda2cd637a
commit
ba45a834e9
20
README.md
20
README.md
|
@ -397,6 +397,26 @@ response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### FileFallBackHandler
|
||||||
|
Example provided by [@sticilface](https://github.com/sticilface)
|
||||||
|
|
||||||
|
This handler is useful for serving content from a CDN when the ESP is connected to a wifi
|
||||||
|
network, but falling back to local copies of the file stored in SPIFFS when the ESP is in
|
||||||
|
AP mode and the client does not have internet access. It will work when both AP mode and
|
||||||
|
STA mode are active. It works by returning 302 HTTP code, with a Location header that
|
||||||
|
you specify. It is much quicker than requiring the ESP to handle all the files.
|
||||||
|
```cpp
|
||||||
|
#include "FileFallbackHandler.h" // include this in the sketch.
|
||||||
|
|
||||||
|
server.addHandler( new FileFallbackHandler(SPIFFS, "/path_to_SPIFFS_file", "/uri", "url_to_forward", "optional_cache_control_header"));
|
||||||
|
|
||||||
|
// These three lines will serve all the jquery requirements from SPIFFS (if they are there) in AP mode, but forward the URL to CDN if not.
|
||||||
|
server.addHandler( new FileFallbackHandler(_fs, "/jquery/jqm1.4.5.css", "/jquery/jqm1.4.5.css", "http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css", "max-age=86400"));
|
||||||
|
server.addHandler( new FileFallbackHandler(_fs, "/jquery/jq1.11.1.js" , "/jquery/jq1.11.1.js" , "http://code.jquery.com/jquery-1.11.1.min.js", "max-age=86400"));
|
||||||
|
server.addHandler( new FileFallbackHandler(_fs, "/jquery/jqm1.4.5.js" , "/jquery/jqm1.4.5.js" , "http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js", "max-age=86400"));
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Bad Responses
|
## Bad Responses
|
||||||
Some responses are implemented, but you should not use them, because they do not conform to HTTP.
|
Some responses are implemented, but you should not use them, because they do not conform to HTTP.
|
||||||
The following example will lead to unclean close of the connection and more time wasted
|
The following example will lead to unclean close of the connection and more time wasted
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "FileFallbackHandler.h"
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
#if defined(ESP31B)
|
||||||
|
#include <ESP31BWiFi.h>
|
||||||
|
#elif defined(ESP8266)
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#else
|
||||||
|
#error Platform not supported
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool FileFallbackHandler::canHandle(AsyncWebServerRequest *request)
|
||||||
|
{
|
||||||
|
if (request->method() != HTTP_GET) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((_isFile && request->url() != _uri) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// if the root of the request matches the _uri then it checks to see if there is a file it can handle.
|
||||||
|
if (request->url().startsWith(_uri)) {
|
||||||
|
String path = _getPath(request);
|
||||||
|
if (_fs.exists(path) || _fs.exists(path + ".gz")) {
|
||||||
|
DEBUGF("[FileFallbackHandler::canHandle] TRUE\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String FileFallbackHandler::_getPath(AsyncWebServerRequest *request)
|
||||||
|
{
|
||||||
|
|
||||||
|
String path = request->url();
|
||||||
|
DEBUGF("[FileFallbackHandler::_getPath]\n");
|
||||||
|
DEBUGF(" [stored] _uri = %s, _path = %s\n" , _uri.c_str(), _path.c_str() ) ;
|
||||||
|
DEBUGF(" [request] url = %s\n", request->url().c_str() );
|
||||||
|
|
||||||
|
if (!_isFile) {
|
||||||
|
DEBUGF(" _isFile = false\n");
|
||||||
|
String baserequestUrl = request->url().substring(_uri.length()); // this is the request - stored _uri... /espman/
|
||||||
|
DEBUGF(" baserequestUrl = %s\n", baserequestUrl.c_str());
|
||||||
|
|
||||||
|
if (!baserequestUrl.length()) {
|
||||||
|
baserequestUrl += "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
path = _path + baserequestUrl;
|
||||||
|
DEBUGF(" path = path + baserequestUrl, path = %s\n", path.c_str());
|
||||||
|
|
||||||
|
if (path.endsWith("/")) {
|
||||||
|
DEBUGF(" 3 path ends with / : path = index.htm \n");
|
||||||
|
path += "index.htm";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
path = _path;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGF(" final path = %s\n", path.c_str());
|
||||||
|
DEBUGF("[FileFallbackHandler::_getPath] END\n\n");
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FileFallbackHandler::handleRequest(AsyncWebServerRequest *request)
|
||||||
|
{
|
||||||
|
|
||||||
|
String path = _getPath(request);
|
||||||
|
|
||||||
|
|
||||||
|
if ( request->client()->localIP() == WiFi.localIP() ) {
|
||||||
|
|
||||||
|
AsyncWebServerResponse *response = request->beginResponse(302); //Sends 404 File Not Found
|
||||||
|
response->addHeader("Location", _forwardUri );
|
||||||
|
if (_cache_header.length() != 0) {
|
||||||
|
response->addHeader("Cache-Control", _cache_header);
|
||||||
|
}
|
||||||
|
request->send(response);
|
||||||
|
|
||||||
|
} else if (_fs.exists(path) || _fs.exists(path + ".gz")) {
|
||||||
|
AsyncWebServerResponse * response = request->beginResponse(_fs, path);
|
||||||
|
if (_cache_header.length() != 0) {
|
||||||
|
response->addHeader("Cache-Control", _cache_header);
|
||||||
|
}
|
||||||
|
request->send(response);
|
||||||
|
} else {
|
||||||
|
request->send(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
path = String();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
// FileFallbackHandler.h
|
||||||
|
/*
|
||||||
|
FileFallbackHandler Response to use with asyncwebserver
|
||||||
|
Written by Andrew Melvin (SticilFace), based on ServeStatic, with help from me-no-dev.
|
||||||
|
|
||||||
|
This handler will serve a 302 response to a client request for a SPIFFS file if the request comes from the STA side of the ESP network.
|
||||||
|
If the request comes from the AP side then it serves the file from SPIFFS.
|
||||||
|
This is useful if you have content that is available from a CDN but you want it to work in AP mode.
|
||||||
|
This also speeds things up a lot as the ESP is not left serving files, and the client can cache them as well.
|
||||||
|
|
||||||
|
|
||||||
|
FileFallbackHandler(SPIFFS, File_location, Uri, fallback_uri, cache_control header (optional) )
|
||||||
|
|
||||||
|
Example of callback in use
|
||||||
|
|
||||||
|
server.addHandler( new FileFallbackHandler(SPIFFS, "/jquery/jqm1.4.5.css", "/jquery/jqm1.4.5.css", "http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css", "max-age=86400"));
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
#ifndef ASYNC_FILEFALLBACK_H_
|
||||||
|
#define ASYNC_FILEFALLBACK_H_
|
||||||
|
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
|
||||||
|
class FileFallbackHandler: public AsyncWebHandler {
|
||||||
|
private:
|
||||||
|
String _getPath(AsyncWebServerRequest *request);
|
||||||
|
protected:
|
||||||
|
FS _fs;
|
||||||
|
String _uri;
|
||||||
|
String _path;
|
||||||
|
String _forwardUri;
|
||||||
|
String _cache_header;
|
||||||
|
bool _isFile;
|
||||||
|
public:
|
||||||
|
FileFallbackHandler(FS& fs, const char* path, const char* uri, const char* forwardUri ,const char* cache_header)
|
||||||
|
: _fs(fs), _uri(uri), _path(path), _forwardUri(forwardUri),_cache_header(cache_header){
|
||||||
|
|
||||||
|
_isFile = _fs.exists(path) || _fs.exists((String(path)+".gz").c_str());
|
||||||
|
if (_uri != "/" && _uri.endsWith("/")) {
|
||||||
|
_uri = _uri.substring(0, _uri.length() - 1);
|
||||||
|
DEBUGF("[FileFallbackHandler] _uri / removed\n");
|
||||||
|
}
|
||||||
|
if (_path != "/" && _path.endsWith("/")) {
|
||||||
|
_path = _path.substring(0, _path.length() - 1);
|
||||||
|
DEBUGF("[FileFallbackHandler] _path / removed\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool canHandle(AsyncWebServerRequest *request);
|
||||||
|
void handleRequest(AsyncWebServerRequest *request);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue