fix: oom exceptions for OPDS, KOSync, and OTA via wolfssl (#2475)

This commit is contained in:
Justin Mitchell
2026-07-12 01:53:26 +03:00
committed by GitHub
parent 1f5669a08a
commit 3e627112f6
13 changed files with 413 additions and 233 deletions
+49 -5
View File
@@ -1,6 +1,29 @@
#include "UrlUtils.h"
#include <cstdio>
namespace UrlUtils {
namespace {
bool isHexDigit(const char c) { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); }
bool shouldEncode(const unsigned char c) {
if (c <= 0x20 || c >= 0x7f) return true;
switch (c) {
case '"':
case '<':
case '>':
case '\\':
case '^':
case '`':
case '{':
case '|':
case '}':
return true;
default:
return false;
}
}
} // namespace
std::string ensureProtocol(const std::string& url) {
if (url.find("://") == std::string::npos) {
@@ -22,18 +45,39 @@ std::string extractHost(const std::string& url) {
return pathStart == std::string::npos ? url : url.substr(0, pathStart);
}
std::string encodeUnsafeUrlChars(const std::string& url) {
std::string out;
out.reserve(url.size());
for (size_t i = 0; i < url.size(); ++i) {
const unsigned char c = static_cast<unsigned char>(url[i]);
if (c == '%' && i + 2 < url.size() && isHexDigit(url[i + 1]) && isHexDigit(url[i + 2])) {
out += url[i];
out += url[i + 1];
out += url[i + 2];
i += 2;
} else if (c == '%' || shouldEncode(c)) {
char encoded[4];
snprintf(encoded, sizeof(encoded), "%%%02X", c);
out += encoded;
} else {
out += static_cast<char>(c);
}
}
return out;
}
std::string buildUrl(const std::string& serverUrl, const std::string& path) {
// If path is already an absolute URL (has protocol), use it directly
if (path.find("://") != std::string::npos) {
return path;
return encodeUnsafeUrlChars(path);
}
const std::string urlWithProtocol = ensureProtocol(serverUrl);
if (path.empty()) {
return urlWithProtocol;
return encodeUnsafeUrlChars(urlWithProtocol);
}
if (path[0] == '/') {
// Absolute path - use just the host
return extractHost(urlWithProtocol) + path;
return encodeUnsafeUrlChars(extractHost(urlWithProtocol) + path);
}
// Relative path - strip query string from base before appending
std::string base = urlWithProtocol;
@@ -42,9 +86,9 @@ std::string buildUrl(const std::string& serverUrl, const std::string& path) {
base.resize(queryPos);
}
if (base.back() == '/') {
return base + path;
return encodeUnsafeUrlChars(base + path);
}
return base + "/" + path;
return encodeUnsafeUrlChars(base + "/" + path);
}
} // namespace UrlUtils
+5
View File
@@ -13,6 +13,11 @@ std::string ensureProtocol(const std::string& url);
*/
std::string extractHost(const std::string& url);
/**
* Percent-encode raw characters that esp_http_client rejects in a URL.
*/
std::string encodeUnsafeUrlChars(const std::string& url);
/**
* Build full URL from server URL and path.
* If path starts with /, it's an absolute path from the host root.