1515
1616#include " src/operators/validate_byte_range.h"
1717
18+ #include < cctype>
19+ #include < cstring>
1820#include < string>
1921#include < memory>
2022
2325namespace modsecurity {
2426namespace operators {
2527
28+ namespace {
29+
30+ std::string trimCopy (const std::string &value) {
31+ std::string::size_type start = 0 ;
32+ std::string::size_type end = value.size ();
33+
34+ while (start < end
35+ && std::isspace (static_cast <unsigned char >(value[start]))) {
36+ start++;
37+ }
38+ while (end > start
39+ && std::isspace (static_cast <unsigned char >(value[end - 1 ]))) {
40+ end--;
41+ }
42+
43+ return value.substr (start, end - start);
44+ }
45+
46+ bool parseStrictInt (const std::string &value, int *result, std::string *error) {
47+ const std::string trimmed = trimCopy (value);
48+
49+ if (trimmed.empty ()) {
50+ error->assign (" Not able to convert '" + value + " ' into a number" );
51+ return false ;
52+ }
53+
54+ size_t pos = 0 ;
55+
56+ try {
57+ *result = std::stoi (trimmed, &pos);
58+ } catch (...) {
59+ error->assign (" Not able to convert '" + trimmed + " ' into a number" );
60+ return false ;
61+ }
62+
63+ if (pos != trimmed.size ()) {
64+ error->assign (" Not able to convert '" + trimmed + " ' into a number" );
65+ return false ;
66+ }
67+
68+ return true ;
69+ }
70+
71+ inline void allowByte (std::array<unsigned char , 32 > *table, int value) {
72+ (*table)[value >> 3 ] = ((*table)[value >> 3 ]
73+ | (1U << static_cast <unsigned char >(value & 0x7 )));
74+ }
75+
76+ } // namespace
77+
78+
2679bool ValidateByteRange::getRange (const std::string &rangeRepresentation,
2780 std::string *error) {
28- size_t pos = rangeRepresentation.find_first_of (" -" );
29- int start;
30- int end;
81+ return getRange (rangeRepresentation, &table, error);
82+ }
83+
84+
85+ bool ValidateByteRange::getRange (const std::string &rangeRepresentation,
86+ std::array<unsigned char , kTableSize > *targetTable,
87+ std::string *error) const {
88+ const std::string range = trimCopy (rangeRepresentation);
89+ const size_t pos = range.find_first_of (" -" );
90+ int start = 0 ;
91+ int end = 0 ;
3192
3293 if (pos == std::string::npos) {
33- try {
34- start = std::stoi (rangeRepresentation);
35- } catch (...) {
36- error->assign (" Not able to convert '" + rangeRepresentation +
37- " ' into a number" );
94+ if (parseStrictInt (range, &start, error) == false ) {
3895 return false ;
3996 }
4097 if ((start < 0 ) || (start > 255 )) {
4198 error->assign (" Invalid byte value: " +
4299 std::to_string (start));
43100 return false ;
44101 }
45- table[start >> 3 ] = (table[start >> 3 ] | ( 1 << ( start & 0x7 )) );
102+ allowByte (targetTable, start);
46103 return true ;
47104 }
48105
49- try {
50- start = std::stoi (std::string (rangeRepresentation, 0 , pos));
51- } catch (...) {
52- error->assign (" Not able to convert '" +
53- std::string (rangeRepresentation, 0 , pos) +
54- " ' into a number" );
106+ if (parseStrictInt (std::string (range, 0 , pos), &start, error) == false ) {
55107 return false ;
56108 }
57109
58- try {
59- end = std::stoi (std::string (rangeRepresentation, pos + 1 ,
60- rangeRepresentation.length () - (pos + 1 )));
61- } catch (...) {
62- error->assign (" Not able to convert '" + std::string (rangeRepresentation,
63- pos + 1 , rangeRepresentation.length () - (pos + 1 )) +
64- " ' into a number" );
110+ if (parseStrictInt (std::string (range, pos + 1 ,
111+ range.length () - (pos + 1 )), &end, error) == false ) {
65112 return false ;
66113 }
67114
@@ -81,7 +128,7 @@ bool ValidateByteRange::getRange(const std::string &rangeRepresentation,
81128 }
82129
83130 while (start <= end) {
84- table[start >> 3 ] = (table[start >> 3 ] | ( 1 << ( start & 0x7 )) );
131+ allowByte (targetTable, start);
85132 start++;
86133 }
87134
@@ -91,34 +138,29 @@ bool ValidateByteRange::getRange(const std::string &rangeRepresentation,
91138
92139bool ValidateByteRange::init (const std::string &file,
93140 std::string *error) {
94- size_t pos = m_param. find_first_of ( " , " ) ;
95- bool rc ;
141+ std::array< unsigned char , kTableSize > parsedTable{} ;
142+ std::string::size_type pos = 0 ;
96143
97- if (pos == std::string::npos) {
98- rc = getRange (m_param, error);
99- } else {
100- rc = getRange (std::string (m_param, 0 , pos), error);
101- }
144+ table.fill (' \0 ' );
102145
103- if (rc == false ) {
104- return false ;
105- }
146+ while (true ) {
147+ const std::string::size_type nextPos = m_param.find (' ,' , pos);
148+ const std::string token = nextPos == std::string::npos
149+ ? m_param.substr (pos)
150+ : m_param.substr (pos, nextPos - pos);
106151
107- while (pos != std::string::npos) {
108- size_t next_pos = m_param.find_first_of (" ," , pos + 1 );
109-
110- if (next_pos == std::string::npos) {
111- rc = getRange (std::string (m_param, pos + 1 , m_param.length () -
112- (pos + 1 )), error);
113- } else {
114- rc = getRange (std::string (m_param, pos + 1 , next_pos - (pos + 1 )), error);
115- }
116- if (rc == false ) {
152+ if (getRange (token, &parsedTable, error) == false ) {
117153 return false ;
118154 }
119- pos = next_pos;
155+
156+ if (nextPos == std::string::npos) {
157+ break ;
158+ }
159+
160+ pos = nextPos + 1 ;
120161 }
121162
163+ table = parsedTable;
122164 return true ;
123165}
124166
0 commit comments