HTTP 302 and 304 Support

Add support for http redirection (302) and http not modified (304) to
reduce the load the server.
server.redirect(“url”, “location”, exclude-ip) will respond with 302 to
redirect the browser to a different url, this is useful for backward
compatibility and to redirect call to CDN when not no AP mode.
server.serveStatic has a new optional parameter to get the
Last-Modified date for all files serve for this location, when the
browser request have the same If-Modified-Since header value, the
server respond with 304 code instead of serving the file.
This commit is contained in:
Hagai Shatz
2016-06-12 11:52:38 +01:00
parent ba45a834e9
commit a01972c9e5
6 changed files with 91 additions and 11 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.idea/

View File

@@ -416,6 +416,38 @@ server.addHandler( new FileFallbackHandler(_fs, "/jquery/jq1.11.1.js" , "/jquery
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"));
```
### Serving static files from SPIFFS
Serve a specific file or attach a folder in SPIFFS to a root url.
An optional Cache-Control header can be added to responses.
An optional Last-Modified header can be added, if the request contains If-Modified-Since header with the same value the server will respond with 304 code instead of serving the file.
```cpp
// Serve static file example
server.serveStatic("/url/file.htm", SPIFFS, "/dir/file.htm");
// Serve static folder example
server.serveStatic("/root-url", SPIFFS, "/root-dir");
// Specify cache control
server.serveStatic("/root-url", SPIFFS, "/root-dir", "max-age=86400");
// Specify last modified (should be updated each time files are updated)
server.serveStatic("/root-url", SPIFFS, "/root-dir", NULL, "Wed, 08 Jun 2016 22:00:00 GMT");
```
### HTTP Redirect (302)
Return HTTP 302 response to redirect the client to a different location.
An optional IPAddress can specify redirection exclusions, for example, exclude redirection to requests to the AP address.
```cpp
// Redirect all requests
server.redirect("/root/file.ext", "/other-location/other-file.ext");
// Redirect requests not for the AP address
server.redirect("/root/file.ext", "/other-location/other-file.ext", WiFi.softAPIP());
// Redirect to jquery CDN except when call is done to AP address
server.redirect("/jquery/jq1.12.3.js", "http://code.jquery.com/jquery-1.12.3.min.js", WiFi.softAPIP());
// Serve the jquery from SPIFFS
server.serveStatic("/jquery", SPIFFS, "/jquery");
```
## Bad Responses
Some responses are implemented, but you should not use them, because they do not conform to HTTP.

View File

@@ -297,7 +297,9 @@ class AsyncWebServer {
void on(const char* uri, WebRequestMethod method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload);
void on(const char* uri, WebRequestMethod method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody);
void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL);
void redirect(const char* url, const char* location, const uint32_t exclude_ip = 0);
void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL, const char* modified_header = NULL);
void onNotFound(ArRequestHandlerFunction fn); //called when handler is not assigned
void onFileUpload(ArUploadHandlerFunction fn); //handle file uploads

View File

@@ -24,6 +24,18 @@
#include "stddef.h"
class RedirectWebHandler: public AsyncWebHandler {
protected:
String _url;
String _location;
uint32_t _exclude_ip;
public:
RedirectWebHandler(const char* url, const char* location, uint32_t exclude_ip)
: _url(url), _location(location) { _exclude_ip = exclude_ip; }
bool canHandle(AsyncWebServerRequest *request);
void handleRequest(AsyncWebServerRequest *request);
};
class AsyncStaticWebHandler: public AsyncWebHandler {
private:
String _getPath(AsyncWebServerRequest *request);
@@ -32,10 +44,11 @@ class AsyncStaticWebHandler: public AsyncWebHandler {
String _uri;
String _path;
String _cache_header;
String _modified_header;
bool _isFile;
public:
AsyncStaticWebHandler(FS& fs, const char* path, const char* uri, const char* cache_header)
: _fs(fs), _uri(uri), _path(path), _cache_header(cache_header){
AsyncStaticWebHandler(FS& fs, const char* path, const char* uri, const char* cache_header, const char* modified_header)
: _fs(fs), _uri(uri), _path(path), _cache_header(cache_header), _modified_header(modified_header) {
_isFile = _fs.exists(path) || _fs.exists((String(path)+".gz").c_str());
if (_uri != "/" && _uri.endsWith("/")) {

View File

@@ -21,6 +21,25 @@
#include "ESPAsyncWebServer.h"
#include "WebHandlerImpl.h"
bool RedirectWebHandler::canHandle(AsyncWebServerRequest *request)
{
// We can redirect when the request url match and ip doesn't match
if (request->url() == _url && _exclude_ip != request->client()->localIP()) {
DEBUGF("[RedirectWebHandler::canHandle] TRUE\n");
return true;
}
return false;
}
void RedirectWebHandler::handleRequest(AsyncWebServerRequest *request)
{
AsyncWebServerResponse *response = request->beginResponse(302);
response->addHeader("Location", _location);
request->send(response);
}
bool AsyncStaticWebHandler::canHandle(AsyncWebServerRequest *request)
{
if (request->method() != HTTP_GET) {
@@ -33,7 +52,10 @@ bool AsyncStaticWebHandler::canHandle(AsyncWebServerRequest *request)
if (request->url().startsWith(_uri)) {
String path = _getPath(request);
if (_fs.exists(path) || _fs.exists(path + ".gz")) {
DEBUGF("[AsyncStaticWebHandler::canHandle] TRUE\n");
if (_modified_header.length() != 0) {
request->addInterestingHeader("If-Modified-Since");
}
DEBUGF("[AsyncStaticWebHandler::canHandle] TRUE\n");
return true;
}
}
@@ -82,14 +104,19 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request)
String path = _getPath(request);
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);
if (_modified_header.length() != 0 && _modified_header == request->header("If-Modified-Since")) {
request->send(304); // Sed not modified
} else {
AsyncWebServerResponse * response = request->beginResponse(_fs, path);
if (_modified_header.length() !=0)
response->addHeader("Last-Modified", _modified_header);
if (_cache_header.length() != 0)
response->addHeader("Cache-Control", _cache_header);
request->send(response);
}
} else {
request->send(404);
}
path = String();
}

View File

@@ -104,8 +104,12 @@ void AsyncWebServer::on(const char* uri, ArRequestHandlerFunction onRequest){
addHandler(handler);
}
void AsyncWebServer::serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header){
addHandler(new AsyncStaticWebHandler(fs, path, uri, cache_header));
void AsyncWebServer::redirect(const char* url, const char* location, const uint32_t exclude_ip){
addHandler(new RedirectWebHandler(url, location, exclude_ip));
}
void AsyncWebServer::serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header, const char* modified_header){
addHandler(new AsyncStaticWebHandler(fs, path, uri, cache_header, modified_header));
}
void AsyncWebServer::onNotFound(ArRequestHandlerFunction fn){