diff --git a/src/web.cpp b/src/web.cpp index defffd3..69763ab 100644 --- a/src/web.cpp +++ b/src/web.cpp @@ -1,8 +1,7 @@ #include "web.h" #include #include - -#define WEB_CONTENT_BUFFER 512 +#include /** * How long to wait after the OK to shutdown before no longer @@ -10,16 +9,23 @@ */ #define WEB_SHUTDOWN_TIME 300000 +void handle_not_found(HttpRequest&, HttpResponse&); +void handle_method_not_allowed(HttpRequest&, HttpResponse&); +void serve_static(const char*, HttpResponse&); + bool web_is_shutdown = false; unsigned long web_shutdown_at = 0; // if non-zero, this is when requests will no longer be responsed to - +// Content buffers for web content +#define WEB_CONTENT_BUFFER 512 uint8_t _content_buffer[WEB_CONTENT_BUFFER] = {}; Buffer content(_content_buffer, WEB_CONTENT_BUFFER); +File contentFile; // Initialize Connection void web_init(HttpRequest& req, HttpResponse& res) { + SPIFFS.begin(); content.clear(); // clear content buffer res.content = &content; // response content buffer } @@ -27,9 +33,28 @@ void web_init(HttpRequest& req, HttpResponse& res) // Terminate Connection void web_terminate(const HttpRequest& req, const HttpResponse& res) { + if (contentFile) contentFile.close(); Serial.printf("[%s] %s %d\r\n", req.getMethod(), req.getUrl(), res.code); } +void handle_index(HttpRequest& req, HttpResponse& res) +{ + res.headers.set("Content-Type","text/html"); + serve_static("/w/index.html", res); +} + +void handle_setup(HttpRequest& req, HttpResponse& res) +{ + res.headers.set("Content-Type", "text/html"); + serve_static("/w/setup.html", res); +} + +void handle_firmware(HttpRequest& req, HttpResponse& res) +{ + res.headers.set("Content-Type", "text/html"); + serve_static("/w/firmware.html", res); +} + // Handle WiFi Scan void handle_wifi_scan(HttpRequest& req, HttpResponse& res) { @@ -59,9 +84,60 @@ void handle_wifi_state(HttpRequest& req, HttpResponse& res) } } +/** + * Handle any request for a static asset + * TODO: remove WString.h dependency + * TODO: F strings + */ +void handle_asset(HttpRequest& req, HttpResponse& res) +{ + String prefix = String("/w"); + String path = String(prefix + req.url); + String gzpath; + + // Determine content type + if (path.endsWith(".html")) + res.headers.set("Content-Type", "text/html;charset=utf-8"); + else if (path.endsWith(".js")) + res.headers.set("Content-Type", "application/x-javascript;charset=utf-8"); + else if (path.endsWith(".css")) + res.headers.set("Content-Type", "text/css;charset=utf-8"); + + // Can we send a GZip version? + bool canGZip = req.headers.in("Accept-Encoding", "gzip"); + if (canGZip) { + gzpath = String(path + ".gz"); + if (SPIFFS.exists(gzpath)) { + path = gzpath; + res.headers.set("Content-Encoding", "gzip"); + } else { + canGZip = false; + } + } + serve_static(path.c_str(), res); +} + +/** + * Serve any static content on the filesystem + */ +void serve_static(const char* path, HttpResponse& res) +{ + contentFile = SPIFFS.open(path, "r"); + if (!contentFile) { // Handle Not Found + res.code = 404; + return; + } + res.headers.set("Cache-Control", "public, max-age=35136000"); + res.content = &contentFile; +} + Route routes[] = { + { GET, "/", handle_index}, + { GET, "/setup", handle_setup}, { GET, "/wifi/scan", handle_wifi_scan}, - { GET | POST | DELETE, "/wifi", handle_wifi_state} + { GET | POST | DELETE, "/wifi", handle_wifi_state}, + { GET | POST, "/firmware", handle_firmware}, + { GET, "/#", handle_asset} }; WebKernel webKernel(80, routes, sizeof(routes)/sizeof(routes[0])); @@ -77,7 +153,7 @@ void uweather_web_init(void) } void uweather_web_handle(void) -{ +{ if (web_is_shutdown) return; if (web_shutdown_at) { unsigned long now = millis();