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:
sticilface 2016-06-10 08:46:12 +01:00 committed by Me No Dev
parent bda2cd637a
commit ba45a834e9
3 changed files with 172 additions and 0 deletions

View File

@ -397,6 +397,26 @@ response->setLength();
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
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

View File

@ -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();
}

55
src/FileFallbackHandler.h Normal file
View File

@ -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