1
0
mirror of https://github.com/thooge/esp32-nmea2000-obp60.git synced 2026-08-18 18:32:30 +02:00

Only decompress zip after a succsessfully contenet download

This commit is contained in:
norbert-walter
2026-02-20 14:54:48 +01:00
parent 25422b77d6
commit c647c2fe44
+50 -17
View File
@@ -105,7 +105,6 @@ bool NetworkClient::httpGetGzip(const String& url, uint8_t*& outData, size_t& ou
return false; return false;
} }
else{ else{
if (DEBUGING) { if (DEBUGING) {
String ce = http.header("Content-Encoding"); String ce = http.header("Content-Encoding");
String te = http.header("Transfer-Encoding"); String te = http.header("Transfer-Encoding");
@@ -132,9 +131,18 @@ bool NetworkClient::httpGetGzip(const String& url, uint8_t*& outData, size_t& ou
String ce = http.header("Content-Encoding"); String ce = http.header("Content-Encoding");
bool isGzip = ce.equalsIgnoreCase("gzip"); bool isGzip = ce.equalsIgnoreCase("gzip");
// NEW: read expected body size if provided by server (prevents waiting forever for missing bytes)
int total = http.getSize(); // returns Content-Length, or -1 if unknown/chunked
// NEW: fail fast if server claims something larger than our buffer
if (total > 0 && (size_t)total > capacity) {
Serial.println("Response exceeds READLIMIT.");
aborting = true;
}
// NEW: if not gzip, we will not try to decompress (prevents false "Decompress OK" / random success) // NEW: if not gzip, we will not try to decompress (prevents false "Decompress OK" / random success)
// You can either handle plain JSON here or just fail-fast. // You can either handle plain JSON here or just fail-fast.
if (!isGzip) { if (!isGzip && !aborting) {
if (DEBUGING) { if (DEBUGING) {
Serial.println("Server response is NOT gzip (Content-Encoding != gzip)."); Serial.println("Server response is NOT gzip (Content-Encoding != gzip).");
Serial.println("Either disable Accept-Encoding: gzip or add plain-body handling here."); Serial.println("Either disable Accept-Encoding: gzip or add plain-body handling here.");
@@ -142,7 +150,6 @@ bool NetworkClient::httpGetGzip(const String& url, uint8_t*& outData, size_t& ou
// --- Plain-body handling (recommended): read full body into outData as-is --- // --- Plain-body handling (recommended): read full body into outData as-is ---
// NEW: try to read Content-Length bytes if available (more robust) // NEW: try to read Content-Length bytes if available (more robust)
int total = http.getSize(); // returns Content-Length, or -1 if unknown/chunked
if (total > 0 && (size_t)total > capacity) { if (total > 0 && (size_t)total > capacity) {
Serial.println("Plain response exceeds READLIMIT."); Serial.println("Plain response exceeds READLIMIT.");
aborting = true; aborting = true;
@@ -175,6 +182,7 @@ bool NetworkClient::httpGetGzip(const String& url, uint8_t*& outData, size_t& ou
lastData = millis(); lastData = millis();
} }
// NEW: stop reading as soon as we have the full response
if (total > 0 && (int)len >= total) { if (total > 0 && (int)len >= total) {
break; // we got full body break; // we got full body
} }
@@ -208,13 +216,21 @@ bool NetworkClient::httpGetGzip(const String& url, uint8_t*& outData, size_t& ou
} }
// --- GZIP path (only if Content-Encoding is gzip) --- // --- GZIP path (only if Content-Encoding is gzip) ---
while ((http.connected() || (stream && stream->available())) && !complete) { if (!aborting) {
// NEW: read exactly Content-Length bytes when available (prevents partial-body timeout loops)
while ((http.connected() || (stream && stream->available())) && !complete && !aborting) {
size_t avail = stream ? stream->available() : 0; size_t avail = stream ? stream->available() : 0;
if (avail == 0) { if (avail == 0) {
// NEW: if Content-Length is known and we already read it all, stop immediately
if (total > 0 && (int)len >= total) {
break;
}
if (millis() - lastData > READ_TIMEOUT) { if (millis() - lastData > READ_TIMEOUT) {
Serial.println("TIMEOUT waiting for data!"); if (DEBUGING) {Serial.println("TIMEOUT waiting for data!");}
aborting = true; // NEW: mark abnormal exit aborting = true; // NEW: mark abnormal exit
break; break;
} }
@@ -229,6 +245,12 @@ bool NetworkClient::httpGetGzip(const String& url, uint8_t*& outData, size_t& ou
break; break;
} }
// NEW: if Content-Length is known, do not read beyond it
if (total > 0) {
size_t remaining = (size_t)total - len;
if (avail > remaining) avail = remaining;
}
if (len + avail > capacity) if (len + avail > capacity)
avail = capacity - len; avail = capacity - len;
@@ -244,34 +266,45 @@ bool NetworkClient::httpGetGzip(const String& url, uint8_t*& outData, size_t& ou
if (DEBUGING) {Serial.printf("Read chunk: %d (total: %d)\n", read, (int)len);} if (DEBUGING) {Serial.printf("Read chunk: %d (total: %d)\n", read, (int)len);}
if (len < 20) continue; // Not enough data for header // NEW: if Content-Length is known and fully received, we can stop reading
if (total > 0 && (int)len >= total) {
break;
}
}
// NEW: only attempt gzip parse/decompress after we have a complete body (when Content-Length is known)
// This avoids wasting heap with repeated malloc/free and reduces fragmentation over long runtimes.
if (!aborting) {
if (len < 20) {
aborting = true;
} else {
int headerOffset = skipGzipHeader(buffer, len); int headerOffset = skipGzipHeader(buffer, len);
if (headerOffset < 0) continue; if (headerOffset < 0) {
aborting = true;
} else {
unsigned long testLen = len * 8; // Dynamic expansion unsigned long testLen = len * 8; // Dynamic expansion
uint8_t* test = (uint8_t*)malloc(testLen); uint8_t* test = (uint8_t*)malloc(testLen);
if (!test) { if (!test) {
// NEW: abort if allocation fails to prevent endless retry loop
Serial.println("Malloc failed test buffer, aborting."); Serial.println("Malloc failed test buffer, aborting.");
aborting = true; aborting = true;
break; } else {
} unsigned long srcLen = (unsigned long)(len - (size_t)headerOffset);
unsigned long srcLen = len - headerOffset;
int res = puff(test, &testLen, buffer + headerOffset, &srcLen); int res = puff(test, &testLen, buffer + headerOffset, &srcLen);
if (res == 0) { if (res == 0) {
if (DEBUGING) {Serial.printf("Decompress OK! Size: %lu bytes\n", testLen);} if (DEBUGING) {Serial.printf("Decompress OK! Size: %lu bytes\n", testLen);}
outData = test; outData = test;
outLen = (size_t)testLen; outLen = (size_t)testLen;
complete = true; complete = true;
break; } else {
}
free(test); free(test);
} }
}
}
}
}
}
// --- Added: Force-close connection only if aborted to avoid TCP RST storms --- // --- Added: Force-close connection only if aborted to avoid TCP RST storms ---
if (aborting && stream) stream->stop(); // NEW: stop() only on abnormal termination if (aborting && stream) stream->stop(); // NEW: stop() only on abnormal termination