Skip to content

Commit ed5e6c4

Browse files
committed
Unescape inputs better
An old upstream change [ci skip]
1 parent 579775d commit ed5e6c4

File tree

1 file changed

+37
-11
lines changed

1 file changed

+37
-11
lines changed

Server/mods/deathmatch/logic/CResource.cpp

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2369,24 +2369,49 @@ ResponseCode CResource::HandleRequest(HttpRequest* ipoHttpRequest, HttpResponse*
23692369
return HTTPRESPONSECODE_200_OK;
23702370
}
23712371

2372-
void Unescape(std::string& str)
2372+
std::string Unescape(std::string_view sv)
23732373
{
2374-
const char* pPercent = strchr(str.c_str(), '%');
2374+
// Converts a character to a hexadecimal value
2375+
auto toHex = [](char c)
2376+
{
2377+
if (c >= '0' && c <= '9')
2378+
return c - '0';
2379+
if (c >= 'a' && c <= 'f')
2380+
return c - 'a' + 10;
2381+
if (c >= 'A' && c <= 'F')
2382+
return c - 'A' + 10;
2383+
return 0;
2384+
};
23752385

2376-
while (pPercent)
2386+
std::string out;
2387+
// String can only shrink here
2388+
// as %?? is collapsed to a single char
2389+
out.reserve(sv.length());
2390+
auto it = sv.begin();
2391+
while (it != sv.end())
23772392
{
2378-
if (pPercent[1] && pPercent[2])
2393+
if (*it == '%')
23792394
{
2380-
int iCharCode = 0;
2381-
sscanf(&pPercent[1], "%02X", &iCharCode);
2382-
str.replace(pPercent - str.c_str(), 3, (char*)&iCharCode);
2383-
pPercent = strchr(pPercent + 3, '%');
2395+
// Avoid reading past the end
2396+
if (std::distance(it, sv.end()) < 3)
2397+
{
2398+
out.push_back(*it++);
2399+
continue;
2400+
}
2401+
// Skip %
2402+
++it;
2403+
// Read two digits/letters and convert to char
2404+
uint8_t digit1 = toHex(*it++);
2405+
uint8_t digit2 = toHex(*it++);
2406+
out.push_back(static_cast<char>(digit1 * 0x10 + digit2));
23842407
}
23852408
else
23862409
{
2387-
break;
2410+
// Push normally
2411+
out.push_back(*it++);
23882412
}
23892413
}
2414+
return out;
23902415
}
23912416

23922417
ResponseCode CResource::HandleRequestCall(HttpRequest* ipoHttpRequest, HttpResponse* ipoHttpResponse, CAccount* pAccount)
@@ -2447,7 +2472,7 @@ ResponseCode CResource::HandleRequestCall(HttpRequest* ipoHttpRequest, HttpRespo
24472472
if (iKey >= 0 && iKey < MAX_INPUT_VARIABLES)
24482473
{
24492474
std::string strValue(pEqual + 1, pAnd - (pEqual + 1));
2450-
Unescape(strValue);
2475+
strValue = Unescape(strValue);
24512476

24522477
if (iKey + 1 > static_cast<int>(vecArguments.size()))
24532478
vecArguments.resize(iKey + 1);
@@ -2463,7 +2488,7 @@ ResponseCode CResource::HandleRequestCall(HttpRequest* ipoHttpRequest, HttpRespo
24632488
}
24642489
}
24652490

2466-
Unescape(strFuncName);
2491+
strFuncName = Unescape(strFuncName);
24672492

24682493
for (CExportedFunction& Exported : m_ExportedFunctions)
24692494
{
@@ -2673,6 +2698,7 @@ ResponseCode CResource::HandleRequestActive(HttpRequest* ipoHttpRequest, HttpRes
26732698
}
26742699

26752700
Unescape(strFile);
2701+
strFile = Unescape(strFile);
26762702

26772703
for (CResourceFile* pResourceFile : m_ResourceFiles)
26782704
{

0 commit comments

Comments
 (0)