fix: oom exceptions for OPDS, KOSync, and OTA via wolfssl (#2475)
This commit is contained in:
+49
-5
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user