Skip to content

Commit 47a9be8

Browse files
committed
Remove unnecessary heap-allocation & copy in Transaction::extractArguments
- utils::urldecode_nonstrict_inplace decodes inplace so key & value, which are values returned by utils::string::ssplit_pair can be just be modified and do not need to be copied. - Updated signature of utils::urldecode_nonstrict_inplace, as its two callers already have std::string values.
1 parent a4e6132 commit 47a9be8

File tree

4 files changed

+43
-83
lines changed

4 files changed

+43
-83
lines changed

src/actions/transformations/url_decode.cc

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,8 @@ UrlDecode::UrlDecode(const std::string &action)
2727
}
2828

2929
bool UrlDecode::transform(std::string &value, const Transaction *trans) const {
30-
int invalid_count = 0;
31-
int changed;
32-
const auto new_len = utils::urldecode_nonstrict_inplace(
33-
(unsigned char*)value.data(),
34-
value.length(),
35-
&invalid_count,
36-
&changed);
37-
38-
value.resize(new_len);
39-
return changed != 0;
30+
int invalid_count;
31+
return utils::urldecode_nonstrict_inplace(value, invalid_count);
4032
}
4133

4234

src/transaction.cc

Lines changed: 12 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -348,46 +348,22 @@ bool Transaction::extractArguments(const std::string &orig,
348348
if (m_rules->m_secArgumentSeparator.m_set) {
349349
sep1 = m_rules->m_secArgumentSeparator.m_value.at(0);
350350
}
351-
std::vector<std::string> key_value_sets = utils::string::ssplit(buf, sep1);
352-
353-
for (std::string t : key_value_sets) {
354-
char sep2 = '=';
355-
size_t key_s = 0;
356-
size_t value_s = 0;
357-
int invalid = 0;
358-
int changed = 0;
359-
360-
std::string key;
361-
std::string value;
362-
std::pair<std::string, std::string> key_value_pair = utils::string::ssplit_pair(t, sep2);
363-
key = key_value_pair.first;
364-
value = key_value_pair.second;
365-
366-
key_s = (key.length() + 1);
367-
value_s = (value.length() + 1);
368-
unsigned char *key_c = reinterpret_cast<unsigned char *>(
369-
calloc(sizeof(char), key_s));
370-
unsigned char *value_c = reinterpret_cast<unsigned char *>(
371-
calloc(sizeof(char), value_s));
372-
373-
memcpy(key_c, key.c_str(), key_s);
374-
memcpy(value_c, value.c_str(), value_s);
375-
376-
key_s = utils::urldecode_nonstrict_inplace(key_c, key_s,
377-
&invalid, &changed);
378-
value_s = utils::urldecode_nonstrict_inplace(value_c, value_s,
379-
&invalid, &changed);
380-
381-
if (invalid) {
351+
const auto key_value_sets = utils::string::ssplit(buf, sep1);
352+
353+
for (const auto &t : key_value_sets) {
354+
const auto sep2 = '=';
355+
auto [key, value] = utils::string::ssplit_pair(t, sep2);
356+
357+
int invalid_count;
358+
utils::urldecode_nonstrict_inplace(key, invalid_count);
359+
utils::urldecode_nonstrict_inplace(value, invalid_count);
360+
361+
if (invalid_count > 0) {
382362
m_variableUrlEncodedError.set("1", m_variableOffset);
383363
}
384364

385-
addArgument(orig, std::string(reinterpret_cast<char *>(key_c), key_s-1),
386-
std::string(reinterpret_cast<char *>(value_c), value_s-1), offset);
365+
addArgument(orig, key, value, offset);
387366
offset = offset + t.size() + 1;
388-
389-
free(key_c);
390-
free(value_c);
391367
}
392368

393369
return true;

src/utils/decode.cc

Lines changed: 27 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,63 +22,55 @@ namespace modsecurity {
2222
namespace utils {
2323

2424

25-
int urldecode_nonstrict_inplace(unsigned char *input,
26-
uint64_t input_len, int *invalid_count, int *changed) {
27-
unsigned char *d = (unsigned char *)input;
28-
uint64_t i, count;
25+
bool urldecode_nonstrict_inplace(std::string &val,
26+
int &invalid_count) {
27+
unsigned char *d = (unsigned char *)val.data();
28+
unsigned char *s = d;
29+
const unsigned char *e = s + val.size();
2930

30-
*changed = 0;
31+
invalid_count = 0;
32+
bool changed = false;
3133

32-
if (input == NULL) {
33-
return -1;
34-
}
35-
36-
i = count = 0;
37-
while (i < input_len) {
38-
if (input[i] == '%') {
34+
while (s != e) {
35+
if (*s == '%') {
3936
/* Character is a percent sign. */
4037

4138
/* Are there enough bytes available? */
42-
if (i + 2 < input_len) {
43-
char c1 = input[i + 1];
44-
char c2 = input[i + 2];
39+
if (s + 2 < e) {
40+
const auto c1 = *(s + 1);
41+
const auto c2 = *(s + 2);
4542
if (VALID_HEX(c1) && VALID_HEX(c2)) {
46-
uint64_t uni = string::x2c(&input[i + 1]);
43+
const auto uni = string::x2c(s + 1);
4744

48-
*d++ = (wchar_t)uni;
49-
count++;
50-
i += 3;
51-
*changed = 1;
45+
*d++ = uni;
46+
s += 3;
47+
changed = true;
5248
} else {
5349
/* Not a valid encoding, skip this % */
54-
*d++ = input[i++];
55-
count++;
56-
(*invalid_count)++;
50+
*d++ = *s++;
51+
invalid_count++;
5752
}
5853
} else {
5954
/* Not enough bytes available, copy the raw bytes. */
60-
*d++ = input[i++];
61-
count++;
62-
(*invalid_count)++;
55+
*d++ = *s++;
56+
invalid_count++;
6357
}
6458
} else {
6559
/* Character is not a percent sign. */
66-
if (input[i] == '+') {
60+
if (*s == '+') {
6761
*d++ = ' ';
68-
*changed = 1;
62+
changed = true;
6963
} else {
70-
*d++ = input[i];
64+
*d++ = *s;
7165
}
72-
count++;
73-
i++;
66+
s++;
7467
}
7568
}
7669

77-
#if 0
78-
*d = '\0';
79-
#endif
70+
if (changed)
71+
val.resize((char*) d - val.c_str());
8072

81-
return count;
73+
return changed;
8274
}
8375

8476

src/utils/decode.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ namespace modsecurity {
2929
namespace utils {
3030

3131

32-
int urldecode_nonstrict_inplace(unsigned char *input,
33-
uint64_t input_len, int *invalid_count, int *changed);
32+
bool urldecode_nonstrict_inplace(std::string &val,
33+
int &invalid_count);
3434
std::string uri_decode(const std::string & sSrc);
3535

3636

0 commit comments

Comments
 (0)