Sending GZIP HTML ~ 120kb+ (suggested enhancement) #3
Description
Before I start out, would just like to say thanks for this library it has helped me very quickly port a lot of work from the ESP to the STM32 platform where I can keep both systems fairly in sync!
I also do not know if this is a generic enhancment for both this repo and the non STM32 repo, that's up to you.
I have a HTML build process using GULP which Inlines, uglifies, minifies all of my HTML, CSS and JS . The output file is a single header file that puts the entire thing into PROGMEM.
#define index_html_gz_len 129855
const char PROGMEM index_html_gz[] = {
0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,....
In both the ESP32 / 8266 the following is used to send this as the index:
server.on(String(F("/index.html")).c_str(), HTTP_GET, [](AsyncWebServerRequest *request){
if(authenticate(request)){
return request->requestAuthentication();
}
//webPage setup
char lastModified[50]; // Variable to hold the last modification datetime of website
sprintf_P(lastModified, PSTR("%s %s GMT"), __DATE__, __TIME__); // Populate the last modification date based on build datetime
if (request->header(F("If-Modified-Since")).equals(lastModified)) {
request->send(304);
} else {
// Dump the byte array in PROGMEM with a 200 HTTP code (OK)
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html"), index_html_gz, index_html_gz_len);
// Tell the browswer the contemnt is Gzipped
response->addHeader(F("Content-Encoding"), F("gzip"));
// And set the last-modified datetime so we can check if we need to send it again next time or not
response->addHeader(F("Last-Modified"), lastModified);
request->send(response);
}
WiFi.scanNetworks(true); //they might request wifi networks at some point
});
Unforunately, this did not work with this library using the send_P command as I expected, the headers were send but no content. I have finally come up with a solution, I doubt that it is optimal, but for me it is working.
void EthernetWebServer::sendContent_P(PGM_P content, size_t size)
{
const char * footer = "\r\n";
if (_chunked)
{
char * chunkSize = (char *) malloc(11);
if (chunkSize)
{
sprintf(chunkSize, "%x%s", size, footer);
_currentClient.write(chunkSize, strlen(chunkSize));
free(chunkSize);
}
}
uint16_t bufSize = 4096;
uint8_t buffer[bufSize];
uint16_t count = size / bufSize;
uint16_t remainder = size % bufSize;
uint16_t i = 0;
for (i = 0; i < count; i++) {
/* code */
memcpy_P(buffer, &content[i*bufSize], bufSize);
_currentClient.write(buffer, bufSize);
}
memcpy_P(buffer, &content[i*bufSize], remainder);
_currentClient.write(buffer, remainder);
if (_chunked)
{
_currentClient.write(footer, 2);
}
}
If there is a better way of doing this I would love to know, but for now I can carry on with my development, happy to offer a PR for something to work from if needed?
Now I can have my fully bootstrapped web interface that I use with my ESP devices. 👍