From 73ba1e49fad1f99aa4a7fde4fdfae8a4136eea01 Mon Sep 17 00:00:00 2001
From: Jeremy Poulter
Date: Sat, 24 Jul 2021 21:29:17 +0100
Subject: [PATCH 1/2] Changed to use ETag/If-None-Match for caching
The date format for the Last-Modified header was wrong and was a bit brute force. Using ETag allows proper caching of the each individual file, even over firmware updates.
Also added the Cache-Control header, to force the browser to check with the WiFi module if the file hase changed before using a cached version.
---
scripts/extra_script.py | 13 +++---
src/web_server_static.cpp | 12 ++---
src/web_static/web_server.assets.js.h | 1 +
src/web_static/web_server.emoncms.jpg.h | 1 +
src/web_static/web_server.favicon-152.png.h | 1 +
src/web_static/web_server.favicon-167.png.h | 1 +
src/web_static/web_server.favicon-16x16.png.h | 1 +
src/web_static/web_server.favicon-180.png.h | 1 +
src/web_static/web_server.favicon-32x32.png.h | 1 +
src/web_static/web_server.home.html.h | 1 +
src/web_static/web_server.home.js.h | 1 +
src/web_static/web_server.lib.js.h | 1 +
src/web_static/web_server.ohm.jpg.h | 1 +
src/web_static/web_server.style.css.h | 1 +
src/web_static/web_server.term.html.h | 1 +
src/web_static/web_server.term.js.h | 1 +
src/web_static/web_server.wifi_portal.html.h | 1 +
src/web_static/web_server.wifi_portal.js.h | 1 +
src/web_static/web_server.wifi_signal_1.svg.h | 1 +
src/web_static/web_server.wifi_signal_2.svg.h | 1 +
src/web_static/web_server.wifi_signal_3.svg.h | 1 +
src/web_static/web_server.wifi_signal_4.svg.h | 1 +
src/web_static/web_server.wifi_signal_5.svg.h | 1 +
src/web_static/web_server.zones.json.h | 1 +
src/web_static/web_server_static_files.h | 44 +++++++++----------
test/basic.http | 4 +-
26 files changed, 59 insertions(+), 36 deletions(-)
diff --git a/scripts/extra_script.py b/scripts/extra_script.py
index 77a85cd2..8b1a2da4 100644
--- a/scripts/extra_script.py
+++ b/scripts/extra_script.py
@@ -1,11 +1,7 @@
from os.path import join, isfile, isdir, basename
from os import listdir, system
-import json
from pprint import pprint
-import re
-import requests
-import subprocess
-import sys
+import hashlib
Import("env")
@@ -29,6 +25,7 @@ def text_to_header(source_file):
for line in original.splitlines():
output += u"\n \"{}\\n\"".format(line.replace('\\', '\\\\').replace('"', '\\"'))
output += ";\n"
+ output += "static const char CONTENT_{}_ETAG[] PROGMEM = \"{}\";\n".format(filename, hashlib.sha256(original.encode('utf-8')).hexdigest())
return output
def binary_to_header(source_file):
@@ -36,10 +33,13 @@ def binary_to_header(source_file):
output = "static const char CONTENT_"+filename+"[] PROGMEM = {\n "
count = 0
+ etag = hashlib.sha256()
+
with open(source_file, "rb") as source_fh:
byte = source_fh.read(1)
while byte != b"":
output += "0x{:02x}, ".format(ord(byte))
+ etag.update(byte)
count += 1
if 16 == count:
output += "\n "
@@ -48,6 +48,7 @@ def binary_to_header(source_file):
byte = source_fh.read(1)
output += "0x00 };\n"
+ output += "static const char CONTENT_{}_ETAG[] PROGMEM = \"{}\";\n".format(filename, etag.hexdigest())
return output
def data_to_header(env, target, source):
@@ -100,7 +101,7 @@ def make_static(env, target, source):
filetype = "JSON"
c_name = get_c_name(out_file)
- output += " { \"/"+out_file+"\", CONTENT_"+c_name+", sizeof(CONTENT_"+c_name+") - 1, _CONTENT_TYPE_"+filetype+" },\n"
+ output += " { \"/"+out_file+"\", CONTENT_"+c_name+", sizeof(CONTENT_"+c_name+") - 1, _CONTENT_TYPE_"+filetype+", CONTENT_"+c_name+"_ETAG },\n"
output += "};\n"
diff --git a/src/web_server_static.cpp b/src/web_server_static.cpp
index e7549534..06695a66 100644
--- a/src/web_server_static.cpp
+++ b/src/web_server_static.cpp
@@ -19,6 +19,7 @@ struct StaticFile
const char *data;
size_t length;
const char *type;
+ const char *etag;
};
#include "web_static/web_server_static_files.h"
@@ -34,9 +35,6 @@ static const char _HOME_PAGE[] PROGMEM = "/home.html";
static const char _WIFI_PAGE[] PROGMEM = "/wifi_portal.html";
#define WIFI_PAGE FPSTR(_WIFI_PAGE)
-static const char _BUILD_TIME[] PROGMEM = __DATE__ " " __TIME__ " GMT";
-#define BUILD_TIME FPSTR(_BUILD_TIME)
-
class StaticFileResponse: public MongooseHttpServerResponse
{
private:
@@ -87,8 +85,10 @@ bool web_static_handle(MongooseHttpServerRequest *request)
{
MongooseHttpServerResponseBasic *response = request->beginResponse();
- MongooseString ifModified = request->headers("If-Modified-Since");
- if(ifModified.equals(BUILD_TIME)) {
+ response->addHeader(F("Cache-Control"), F("public, max-age=30, must-revalidate"));
+
+ MongooseString ifNoneMatch = request->headers("If-None-Match");
+ if(ifNoneMatch.equals(file->etag)) {
request->send(304);
return true;
}
@@ -101,7 +101,7 @@ bool web_static_handle(MongooseHttpServerRequest *request)
response->addHeader(F("Access-Control-Allow-Origin"), F("*"));
}
- response->addHeader("Last-Modified", BUILD_TIME);
+ response->addHeader("Etag", file->etag);
response->setContent((const uint8_t *)file->data, file->length);
request->send(response);
diff --git a/src/web_static/web_server.assets.js.h b/src/web_static/web_server.assets.js.h
index 11abecfc..0d84edb4 100644
--- a/src/web_static/web_server.assets.js.h
+++ b/src/web_static/web_server.assets.js.h
@@ -1,2 +1,3 @@
static const char CONTENT_ASSETS_JS[] PROGMEM =
"!function(r){var n={};function o(e){if(n[e])return n[e].exports;var t=n[e]={i:e,l:!1,exports:{}};return r[e].call(t.exports,t,t.exports,o),t.l=!0,t.exports}o.m=r,o.c=n,o.d=function(e,t,r){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},o.r=function(e){\"undefined\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},o.t=function(t,e){if(1&e&&(t=o(t)),8&e)return t;if(4&e&&\"object\"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(o.r(r),Object.defineProperty(r,\"default\",{enumerable:!0,value:t}),2&e&&\"string\"!=typeof t)for(var n in t)o.d(r,n,function(e){return t[e]}.bind(null,n));return r},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,\"a\",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p=\"\",o(o.s=0)}([function(e,t,r){\"use strict\";r.r(t);r(1)},function(e,t,r){}]);\n";
+static const char CONTENT_ASSETS_JS_ETAG[] PROGMEM = "837f049a68283a7e286faa6915b5c7d8cf49e0fc90152592dd1d0c81b5a3a6bf";
diff --git a/src/web_static/web_server.emoncms.jpg.h b/src/web_static/web_server.emoncms.jpg.h
index e1dbc02f..efb33d8b 100644
--- a/src/web_static/web_server.emoncms.jpg.h
+++ b/src/web_static/web_server.emoncms.jpg.h
@@ -157,3 +157,4 @@ static const char CONTENT_EMONCMS_JPG[] PROGMEM = {
0x04, 0x78, 0x86, 0x20, 0x2d, 0x23, 0x9e, 0xf5, 0x0f, 0x9d, 0xa3, 0x86, 0x4e, 0x31, 0x72, 0x61,
0x3f, 0xcb, 0x08, 0x7b, 0x92, 0x59, 0x79, 0xe7, 0xc8, 0x53, 0x36, 0x77, 0x0a, 0x33, 0x1a, 0xe0,
0x75, 0x7a, 0xac, 0xab, 0xe5, 0x7f, 0x43, 0x5f, 0x9f, 0xff, 0xd9, 0x00 };
+static const char CONTENT_EMONCMS_JPG_ETAG[] PROGMEM = "2d8b327212b657791147a1a0b4f047ea068e97850272d10ce982adcd705d6805";
diff --git a/src/web_static/web_server.favicon-152.png.h b/src/web_static/web_server.favicon-152.png.h
index c919694b..a1e1e941 100644
--- a/src/web_static/web_server.favicon-152.png.h
+++ b/src/web_static/web_server.favicon-152.png.h
@@ -149,3 +149,4 @@ static const char CONTENT_FAVICON_152_PNG[] PROGMEM = {
0x54, 0x98, 0x0a, 0x53, 0x61, 0x2a, 0x4c, 0x85, 0xa9, 0x30, 0x15, 0xa6, 0xc2, 0x54, 0x18, 0x36,
0xfe, 0x03, 0x41, 0xf7, 0xc7, 0x3c, 0xd0, 0xda, 0x1a, 0x12, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0x00 };
+static const char CONTENT_FAVICON_152_PNG_ETAG[] PROGMEM = "6bb51a4549bd1a410f20cccd544771491b350d22f4d1ddf4ddc726c26faaf3ef";
diff --git a/src/web_static/web_server.favicon-167.png.h b/src/web_static/web_server.favicon-167.png.h
index 493936c6..a4fa7285 100644
--- a/src/web_static/web_server.favicon-167.png.h
+++ b/src/web_static/web_server.favicon-167.png.h
@@ -163,3 +163,4 @@ static const char CONTENT_FAVICON_167_PNG[] PROGMEM = {
0xa6, 0xd3, 0x74, 0x9a, 0x4e, 0xd3, 0x69, 0x3a, 0x4d, 0xa7, 0xe9, 0x34, 0x9d, 0xa6, 0xd3, 0x74,
0x9a, 0xce, 0xbe, 0x8e, 0xff, 0x00, 0xb7, 0x45, 0xa5, 0xa6, 0x7f, 0x7f, 0xa7, 0x4b, 0x00, 0x00,
0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0x00 };
+static const char CONTENT_FAVICON_167_PNG_ETAG[] PROGMEM = "c04aabe76eafbcfc4f9c90b5036359aace07ae2e07f1712311e19c0a87868978";
diff --git a/src/web_static/web_server.favicon-16x16.png.h b/src/web_static/web_server.favicon-16x16.png.h
index 9d7b4f0f..55ba7fac 100644
--- a/src/web_static/web_server.favicon-16x16.png.h
+++ b/src/web_static/web_server.favicon-16x16.png.h
@@ -42,3 +42,4 @@ static const char CONTENT_FAVICON_16X16_PNG[] PROGMEM = {
0x94, 0x1b, 0xf4, 0xf5, 0xf9, 0xf7, 0xc6, 0xfb, 0xb0, 0x00, 0x34, 0x06, 0x06, 0x1a, 0x7e, 0xc7,
0xc4, 0x51, 0xbf, 0xf3, 0x2f, 0xa4, 0x85, 0xfd, 0x2b, 0x20, 0x03, 0xac, 0x8a, 0x00, 0x00, 0x00,
0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0x00 };
+static const char CONTENT_FAVICON_16X16_PNG_ETAG[] PROGMEM = "c282688b944a78e5ccf6a176f3f4b3cfa85fc157cf7eb215d73543b037416cdc";
diff --git a/src/web_static/web_server.favicon-180.png.h b/src/web_static/web_server.favicon-180.png.h
index fda80c9e..e60d5c5c 100644
--- a/src/web_static/web_server.favicon-180.png.h
+++ b/src/web_static/web_server.favicon-180.png.h
@@ -172,3 +172,4 @@ static const char CONTENT_FAVICON_180_PNG[] PROGMEM = {
0xd1, 0x26, 0xda, 0x44, 0x9b, 0x68, 0x13, 0x6d, 0xa2, 0x4d, 0xb4, 0x89, 0x36, 0xd1, 0x26, 0xda,
0x44, 0x3f, 0xd7, 0xe8, 0xff, 0x01, 0xfb, 0x6b, 0x1c, 0x61, 0xb6, 0x3a, 0x07, 0xa2, 0x00, 0x00,
0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0x00 };
+static const char CONTENT_FAVICON_180_PNG_ETAG[] PROGMEM = "5f88008c6f89bd97a14d56abb3e78c0cf368216a8715b155d6720535159f54fa";
diff --git a/src/web_static/web_server.favicon-32x32.png.h b/src/web_static/web_server.favicon-32x32.png.h
index ea7ee7c2..2ab44926 100644
--- a/src/web_static/web_server.favicon-32x32.png.h
+++ b/src/web_static/web_server.favicon-32x32.png.h
@@ -77,3 +77,4 @@ static const char CONTENT_FAVICON_32X32_PNG[] PROGMEM = {
0x94, 0x28, 0x9a, 0xe3, 0xb9, 0x90, 0x59, 0xfb, 0xff, 0xe3, 0xf4, 0x61, 0x0b, 0xf8, 0x1b, 0x89,
0xbc, 0xd3, 0x48, 0xe7, 0x1c, 0x1e, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
0x42, 0x60, 0x82, 0x00 };
+static const char CONTENT_FAVICON_32X32_PNG_ETAG[] PROGMEM = "b95eba8ce98b49dd982be70a4aaf033cbce086e033b34d2f20f14bfcff25d631";
diff --git a/src/web_static/web_server.home.html.h b/src/web_static/web_server.home.html.h
index c688c213..57df8038 100644
--- a/src/web_static/web_server.home.html.h
+++ b/src/web_static/web_server.home.html.h
@@ -72,3 +72,4 @@ static const char CONTENT_HOME_HTML[] PROGMEM =
" click: vehicle.tesla.logout,\n"
" text: (vehicle.tesla.fetching() ? 'Saving' : (vehicle.tesla.success() ? 'Saved' : 'Logout')),\n"
" disable: vehicle.tesla.fetching\"> Logout
Error
Status
Status | |
Battery Level: | |
Battery Range: | |
Time to full charge: | |