2727namespace modsecurity ::actions::transformations {
2828
2929
30- bool HtmlEntityDecode::transform (std::string &value, const Transaction *trans) const {
31- std::string ret;
32- unsigned char *input;
33-
34- input = reinterpret_cast <unsigned char *>
35- (malloc (sizeof (char ) * value.length ()+1 ));
36-
37- if (input == NULL ) {
38- return " " ;
39- }
40-
41- memcpy (input, value.c_str (), value.length ()+1 );
42-
43- size_t i = inplace (input, value.length ());
44-
45- ret.assign (reinterpret_cast <char *>(input), i);
46- free (input);
47-
48- const auto changed = ret != value;
49- value = ret;
50- return changed;
51- }
52-
30+ static inline bool inplace (std::string &value) {
31+ const auto input_len = value.length ();
32+ auto d = reinterpret_cast <unsigned char *>(value.data ());
33+ const unsigned char *input = d;
34+ const unsigned char *end = input + input_len;
5335
54- int HtmlEntityDecode::inplace (unsigned char *input, uint64_t input_len) {
55- unsigned char *d = input;
56- int i, count;
57-
58- if ((input == NULL ) || (input_len == 0 )) {
59- return 0 ;
60- }
61-
62- i = count = 0 ;
63- while ((i < input_len) && (count < input_len)) {
64- int z, copy = 1 ;
36+ std::string::size_type i = 0 ;
37+ while (i < input_len) {
38+ std::string::size_type copy = 1 ;
6539
6640 /* Require an ampersand and at least one character to
6741 * start looking into the entity.
6842 */
6943 if ((input[i] == ' &' ) && (i + 1 < input_len)) {
70- int k, j = i + 1 ;
44+ auto j = i + 1 ;
7145
7246 if (input[j] == ' #' ) {
7347 /* Numerical entity. */
@@ -87,19 +61,18 @@ int HtmlEntityDecode::inplace(unsigned char *input, uint64_t input_len) {
8761 }
8862 j++; /* j is the position of the first digit now. */
8963
90- k = j;
91- while ((j < input_len) && (isxdigit (input[j]))) {
64+ constexpr int MAX_HEX_DIGITS = 2 ; // supports only bytes (max value 0xff)
65+ auto k = j;
66+ while ((j - k < MAX_HEX_DIGITS) && (j < input_len) && (isxdigit (input[j]))) {
9267 j++;
9368 }
9469 if (j > k) { /* Do we have at least one digit? */
9570 /* Decode the entity. */
96- char *x;
97- x = reinterpret_cast <char *>(calloc (sizeof (char ),
98- ((j - k) + 1 )));
71+ char x[MAX_HEX_DIGITS + 1 ];
9972 memcpy (x, (const char *)&input[k], j - k);
100- *d++ = ( unsigned char ) strtol (x, NULL , 16 ) ;
101- free (x);
102- count++ ;
73+ x[j - k] = ' \0 ' ;
74+
75+ *d++ = ( unsigned char ) strtol (x, nullptr , 16 ) ;
10376
10477 /* Skip over the semicolon if it's there. */
10578 if ((j < input_len) && (input[j] == ' ;' )) {
@@ -113,19 +86,18 @@ int HtmlEntityDecode::inplace(unsigned char *input, uint64_t input_len) {
11386 }
11487 } else {
11588 /* Decimal entity. */
116- k = j;
117- while ((j < input_len) && (isdigit (input[j]))) {
89+ constexpr int MAX_DEC_DIGITS = 3 ; // supports only bytes (max value 255)
90+ auto k = j;
91+ while ((j - k < MAX_DEC_DIGITS) && (j < input_len) && (isdigit (input[j]))) {
11892 j++;
11993 }
12094 if (j > k) { /* Do we have at least one digit? */
12195 /* Decode the entity. */
122- char *x;
123- x = reinterpret_cast <char *>(calloc (sizeof (char ),
124- ((j - k) + 1 )));
96+ char x[MAX_DEC_DIGITS + 1 ];
12597 memcpy (x, (const char *)&input[k], j - k);
126- *d++ = ( unsigned char ) strtol (x, NULL , 10 ) ;
127- free (x);
128- count++ ;
98+ x[j - k] = ' \0 ' ;
99+
100+ *d++ = ( unsigned char ) strtol (x, nullptr , 10 ) ;
129101
130102 /* Skip over the semicolon if it's there. */
131103 if ((j < input_len) && (input[j] == ' ;' )) {
@@ -140,38 +112,31 @@ int HtmlEntityDecode::inplace(unsigned char *input, uint64_t input_len) {
140112 }
141113 } else {
142114 /* Text entity. */
143- k = j;
115+ auto k = j;
144116 while ((j < input_len) && (isalnum (input[j]))) {
145117 j++;
146118 }
147119 if (j > k) { /* Do we have at least one digit? */
148- char *x;
149- x = reinterpret_cast <char *>(calloc (sizeof (char ),
150- ((j - k) + 1 )));
151- memcpy (x, (const char *)&input[k], j - k);
120+ const auto x = reinterpret_cast <const char *>(&input[k]);
152121
153122 /* Decode the entity. */
154123 /* ENH What about others? */
155- if (strcasecmp (x, " quot" ) == 0 ) {
124+ if (strncasecmp (x, " quot" , 4 ) == 0 ) {
156125 *d++ = ' "' ;
157- } else if (strcasecmp (x, " amp" ) == 0 ) {
126+ } else if (strncasecmp (x, " amp" , 3 ) == 0 ) {
158127 *d++ = ' &' ;
159- } else if (strcasecmp (x, " lt" ) == 0 ) {
128+ } else if (strncasecmp (x, " lt" , 2 ) == 0 ) {
160129 *d++ = ' <' ;
161- } else if (strcasecmp (x, " gt" ) == 0 ) {
130+ } else if (strncasecmp (x, " gt" , 2 ) == 0 ) {
162131 *d++ = ' >' ;
163- } else if (strcasecmp (x, " nbsp" ) == 0 ) {
132+ } else if (strncasecmp (x, " nbsp" , 4 ) == 0 ) {
164133 *d++ = NBSP;
165134 } else {
166135 /* We do no want to convert this entity,
167136 * copy the raw data over. */
168137 copy = j - k + 1 ;
169- free (x);
170138 goto HTML_ENT_OUT;
171139 }
172- free (x);
173-
174- count++;
175140
176141 /* Skip over the semicolon if it's there. */
177142 if ((j < input_len) && (input[j] == ' ;' )) {
@@ -187,15 +152,20 @@ int HtmlEntityDecode::inplace(unsigned char *input, uint64_t input_len) {
187152
188153HTML_ENT_OUT:
189154
190- for (z = 0 ; (( z < copy) && (count < input_len)) ; z++) {
155+ for (auto z = 0 ; z < copy; z++) {
191156 *d++ = input[i++];
192- count++;
193157 }
194158 }
195159
196160 *d = ' \0 ' ;
197161
198- return count;
162+ value.resize (d - input);
163+ return d != end;
164+ }
165+
166+
167+ bool HtmlEntityDecode::transform (std::string &value, const Transaction *trans) const {
168+ return inplace (value);
199169}
200170
201171
0 commit comments