/src/PcapPlusPlus/Packet++/src/TextBasedProtocol.cpp
Line | Count | Source |
1 | | #include "TextBasedProtocol.h" |
2 | | #include "Logger.h" |
3 | | #include "PayloadLayer.h" |
4 | | #include <cstring> |
5 | | #include <algorithm> |
6 | | #include <utility> |
7 | | |
8 | | namespace pcpp |
9 | | { |
10 | | |
11 | | // this implementation of strnlen is required since mingw doesn't have strnlen |
12 | | size_t tbp_my_own_strnlen(const char* s, size_t maxlen) |
13 | 96.1k | { |
14 | 96.1k | if (s == nullptr || maxlen == 0) |
15 | 24.0k | return 0; |
16 | | |
17 | 72.0k | size_t i = 0; |
18 | 1.84M | for (; (i < maxlen) && s[i]; ++i) |
19 | 1.76M | ; |
20 | 72.0k | return i; |
21 | 96.1k | } |
22 | | |
23 | | // -------- Class TextBasedProtocolMessage ----------------- |
24 | | |
25 | | TextBasedProtocolMessage::TextBasedProtocolMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, |
26 | | ProtocolType protocol) |
27 | 264k | : Layer(data, dataLen, prevLayer, packet, protocol), m_FieldList(nullptr), m_LastField(nullptr), |
28 | 264k | m_FieldsOffset(0) |
29 | 264k | {} |
30 | | |
31 | 4.34k | TextBasedProtocolMessage::TextBasedProtocolMessage(const TextBasedProtocolMessage& other) : Layer(other) |
32 | 4.34k | { |
33 | 4.34k | copyDataFrom(other); |
34 | 4.34k | } |
35 | | |
36 | | TextBasedProtocolMessage& TextBasedProtocolMessage::operator=(const TextBasedProtocolMessage& other) |
37 | 0 | { |
38 | 0 | Layer::operator=(other); |
39 | 0 | HeaderField* curField = m_FieldList; |
40 | 0 | while (curField != nullptr) |
41 | 0 | { |
42 | 0 | HeaderField* temp = curField; |
43 | 0 | curField = curField->getNextField(); |
44 | 0 | delete temp; |
45 | 0 | } |
46 | |
|
47 | 0 | copyDataFrom(other); |
48 | |
|
49 | 0 | return *this; |
50 | 0 | } |
51 | | |
52 | | void TextBasedProtocolMessage::copyDataFrom(const TextBasedProtocolMessage& other) |
53 | 4.34k | { |
54 | | // copy field list |
55 | 4.34k | if (other.m_FieldList != nullptr) |
56 | 4.34k | { |
57 | 4.34k | m_FieldList = new HeaderField(*(other.m_FieldList)); |
58 | 4.34k | HeaderField* curField = m_FieldList; |
59 | 4.34k | curField->attachToTextBasedProtocolMessage(this, other.m_FieldList->m_NameOffsetInMessage); |
60 | 4.34k | HeaderField* curOtherField = other.m_FieldList; |
61 | 51.9k | while (curOtherField->getNextField() != nullptr) |
62 | 47.6k | { |
63 | 47.6k | HeaderField* newField = new HeaderField(*(curOtherField->getNextField())); |
64 | 47.6k | newField->attachToTextBasedProtocolMessage(this, curOtherField->getNextField()->m_NameOffsetInMessage); |
65 | 47.6k | curField->setNextField(newField); |
66 | 47.6k | curField = curField->getNextField(); |
67 | 47.6k | curOtherField = curOtherField->getNextField(); |
68 | 47.6k | } |
69 | | |
70 | 4.34k | m_LastField = curField; |
71 | 4.34k | } |
72 | 0 | else |
73 | 0 | { |
74 | 0 | m_FieldList = nullptr; |
75 | 0 | m_LastField = nullptr; |
76 | 0 | } |
77 | | |
78 | 4.34k | m_FieldsOffset = other.m_FieldsOffset; |
79 | | |
80 | | // copy map |
81 | 56.3k | for (HeaderField* field = m_FieldList; field != nullptr; field = field->getNextField()) |
82 | 51.9k | { |
83 | 51.9k | m_FieldNameToFieldMap.insert(std::pair<std::string, HeaderField*>(field->getFieldName(), field)); |
84 | 51.9k | } |
85 | 4.34k | } |
86 | | |
87 | | void TextBasedProtocolMessage::parseFields() |
88 | 264k | { |
89 | 264k | char nameValueSeparator = getHeaderFieldNameValueSeparator(); |
90 | 264k | bool spacesAllowedBetweenNameAndValue = spacesAllowedBetweenHeaderFieldNameAndValue(); |
91 | | |
92 | 264k | HeaderField* firstField = |
93 | 264k | new HeaderField(this, m_FieldsOffset, nameValueSeparator, spacesAllowedBetweenNameAndValue); |
94 | 264k | PCPP_LOG_DEBUG("Added new field: name='" << firstField->getFieldName() |
95 | 264k | << "'; offset in packet=" << firstField->m_NameOffsetInMessage |
96 | 264k | << "; length=" << firstField->getFieldSize()); |
97 | 264k | PCPP_LOG_DEBUG(" Field value = " << firstField->getFieldValue()); |
98 | | |
99 | 264k | if (m_FieldList == nullptr) |
100 | 264k | m_FieldList = firstField; |
101 | 0 | else |
102 | 0 | m_FieldList->setNextField(firstField); |
103 | | |
104 | 264k | std::string fieldName = firstField->getFieldName(); |
105 | 264k | std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), ::tolower); |
106 | 264k | m_FieldNameToFieldMap.insert(std::pair<std::string, HeaderField*>(fieldName, firstField)); |
107 | | |
108 | | // Last field will be empty and contain just "\n" or "\r\n". This field will mark the end of the header |
109 | 264k | HeaderField* curField = m_FieldList; |
110 | 264k | int curOffset = m_FieldsOffset; |
111 | | // last field can be one of: |
112 | | // a.) \r\n\r\n or \n\n marking the end of the header |
113 | | // b.) the end of the packet |
114 | 1.99M | while (!curField->isEndOfHeader() && curOffset + curField->getFieldSize() < m_DataLen) |
115 | 1.75M | { |
116 | 1.75M | curOffset += curField->getFieldSize(); |
117 | 1.75M | HeaderField* newField = |
118 | 1.75M | new HeaderField(this, curOffset, nameValueSeparator, spacesAllowedBetweenNameAndValue); |
119 | 1.75M | if (newField->getFieldSize() > 0) |
120 | 1.73M | { |
121 | 1.73M | PCPP_LOG_DEBUG("Added new field: name='" << newField->getFieldName() |
122 | 1.73M | << "'; offset in packet=" << newField->m_NameOffsetInMessage |
123 | 1.73M | << "; length=" << newField->getFieldSize()); |
124 | 1.73M | PCPP_LOG_DEBUG(" Field value = " << newField->getFieldValue()); |
125 | 1.73M | curField->setNextField(newField); |
126 | 1.73M | curField = newField; |
127 | 1.73M | fieldName = newField->getFieldName(); |
128 | 1.73M | std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), ::tolower); |
129 | 1.73M | m_FieldNameToFieldMap.insert(std::pair<std::string, HeaderField*>(fieldName, newField)); |
130 | 1.73M | } |
131 | 22.7k | else |
132 | 22.7k | { |
133 | 22.7k | delete newField; |
134 | 22.7k | break; |
135 | 22.7k | } |
136 | 1.75M | } |
137 | | |
138 | 264k | m_LastField = curField; |
139 | 264k | } |
140 | | |
141 | | TextBasedProtocolMessage::~TextBasedProtocolMessage() |
142 | 269k | { |
143 | 2.32M | while (m_FieldList != nullptr) |
144 | 2.05M | { |
145 | 2.05M | HeaderField* temp = m_FieldList; |
146 | 2.05M | m_FieldList = m_FieldList->getNextField(); |
147 | 2.05M | delete temp; |
148 | 2.05M | } |
149 | 269k | } |
150 | | |
151 | | HeaderField* TextBasedProtocolMessage::addField(const std::string& fieldName, const std::string& fieldValue) |
152 | 10.1k | { |
153 | 10.1k | HeaderField newField(fieldName, fieldValue, getHeaderFieldNameValueSeparator(), |
154 | 10.1k | spacesAllowedBetweenHeaderFieldNameAndValue()); |
155 | 10.1k | return addField(newField); |
156 | 10.1k | } |
157 | | |
158 | | HeaderField* TextBasedProtocolMessage::addField(const HeaderField& newField) |
159 | 10.1k | { |
160 | 10.1k | return insertField(m_LastField, newField); |
161 | 10.1k | } |
162 | | |
163 | | HeaderField* TextBasedProtocolMessage::addEndOfHeader() |
164 | 0 | { |
165 | 0 | HeaderField endOfHeaderField(PCPP_END_OF_TEXT_BASED_PROTOCOL_HEADER, "", '\0', false); |
166 | 0 | return insertField(m_LastField, endOfHeaderField); |
167 | 0 | } |
168 | | |
169 | | HeaderField* TextBasedProtocolMessage::insertField(HeaderField* prevField, const std::string& fieldName, |
170 | | const std::string& fieldValue) |
171 | 0 | { |
172 | 0 | HeaderField newField(fieldName, fieldValue, getHeaderFieldNameValueSeparator(), |
173 | 0 | spacesAllowedBetweenHeaderFieldNameAndValue()); |
174 | 0 | return insertField(prevField, newField); |
175 | 0 | } |
176 | | |
177 | | HeaderField* TextBasedProtocolMessage::insertField(std::string prevFieldName, const std::string& fieldName, |
178 | | const std::string& fieldValue) |
179 | 0 | { |
180 | 0 | if (prevFieldName == "") |
181 | 0 | { |
182 | 0 | return insertField(nullptr, fieldName, fieldValue); |
183 | 0 | } |
184 | 0 | else |
185 | 0 | { |
186 | 0 | HeaderField* prevField = getFieldByName(prevFieldName); |
187 | 0 | if (prevField == nullptr) |
188 | 0 | return nullptr; |
189 | | |
190 | 0 | return insertField(prevField, fieldName, fieldValue); |
191 | 0 | } |
192 | 0 | } |
193 | | |
194 | | HeaderField* TextBasedProtocolMessage::insertField(HeaderField* prevField, const HeaderField& newField) |
195 | 10.1k | { |
196 | 10.1k | if (newField.m_TextBasedProtocolMessage != nullptr) |
197 | 0 | { |
198 | 0 | PCPP_LOG_ERROR("This field is already associated with another message"); |
199 | 0 | return nullptr; |
200 | 0 | } |
201 | | |
202 | 10.1k | if (prevField != nullptr && prevField->getFieldName() == PCPP_END_OF_TEXT_BASED_PROTOCOL_HEADER) |
203 | 3.09k | { |
204 | 3.09k | PCPP_LOG_ERROR("Cannot add a field after end of header"); |
205 | 3.09k | return nullptr; |
206 | 3.09k | } |
207 | | |
208 | 7.08k | HeaderField* newFieldToAdd = new HeaderField(newField); |
209 | | |
210 | 7.08k | int newFieldOffset = m_FieldsOffset; |
211 | 7.08k | if (prevField != nullptr) |
212 | 7.08k | newFieldOffset = prevField->m_NameOffsetInMessage + prevField->getFieldSize(); |
213 | | |
214 | | // extend layer to make room for the new field. Field will be added just before the last field |
215 | 7.08k | if (!extendLayer(newFieldOffset, newFieldToAdd->getFieldSize())) |
216 | 2.63k | { |
217 | 2.63k | PCPP_LOG_ERROR("Cannot extend layer to insert the header"); |
218 | 2.63k | delete newFieldToAdd; |
219 | 2.63k | return nullptr; |
220 | 2.63k | } |
221 | | |
222 | 4.44k | HeaderField* curField = m_FieldList; |
223 | 4.44k | if (prevField != nullptr) |
224 | 4.44k | curField = prevField->getNextField(); |
225 | | |
226 | | // go over all fields after prevField and update their offsets |
227 | 4.44k | shiftFieldsOffset(curField, newFieldToAdd->getFieldSize()); |
228 | | |
229 | | // copy new field data to message |
230 | 4.44k | memcpy(m_Data + newFieldOffset, newFieldToAdd->m_NewFieldData, newFieldToAdd->getFieldSize()); |
231 | | |
232 | | // attach new field to message |
233 | 4.44k | newFieldToAdd->attachToTextBasedProtocolMessage(this, newFieldOffset); |
234 | | |
235 | | // insert field into fields link list |
236 | 4.44k | if (prevField == nullptr) |
237 | 0 | { |
238 | 0 | newFieldToAdd->setNextField(m_FieldList); |
239 | 0 | m_FieldList = newFieldToAdd; |
240 | 0 | } |
241 | 4.44k | else |
242 | 4.44k | { |
243 | 4.44k | newFieldToAdd->setNextField(prevField->getNextField()); |
244 | 4.44k | prevField->setNextField(newFieldToAdd); |
245 | 4.44k | } |
246 | | |
247 | | // if newField is the last field, update m_LastField |
248 | 4.44k | if (newFieldToAdd->getNextField() == nullptr) |
249 | 4.44k | m_LastField = newFieldToAdd; |
250 | | |
251 | | // insert the new field into name to field map |
252 | 4.44k | std::string fieldName = newFieldToAdd->getFieldName(); |
253 | 4.44k | std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), ::tolower); |
254 | 4.44k | m_FieldNameToFieldMap.insert(std::pair<std::string, HeaderField*>(fieldName, newFieldToAdd)); |
255 | | |
256 | 4.44k | return newFieldToAdd; |
257 | 7.08k | } |
258 | | |
259 | | bool TextBasedProtocolMessage::removeField(std::string fieldName, int index) |
260 | 4.34k | { |
261 | 4.34k | std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), ::tolower); |
262 | | |
263 | 4.34k | HeaderField* fieldToRemove = nullptr; |
264 | | |
265 | 4.34k | auto range = m_FieldNameToFieldMap.equal_range(fieldName); |
266 | 4.34k | int i = 0; |
267 | 4.34k | for (std::multimap<std::string, HeaderField*>::iterator iter = range.first; iter != range.second; ++iter) |
268 | 3.75k | { |
269 | 3.75k | if (i == index) |
270 | 3.75k | { |
271 | 3.75k | fieldToRemove = iter->second; |
272 | 3.75k | break; |
273 | 3.75k | } |
274 | | |
275 | 0 | i++; |
276 | 0 | } |
277 | | |
278 | 4.34k | if (fieldToRemove != nullptr) |
279 | 3.75k | return removeField(fieldToRemove); |
280 | 591 | else |
281 | 591 | { |
282 | 591 | PCPP_LOG_ERROR("Cannot find field '" << fieldName << "'"); |
283 | 591 | return false; |
284 | 591 | } |
285 | 4.34k | } |
286 | | |
287 | | bool TextBasedProtocolMessage::removeField(HeaderField* fieldToRemove) |
288 | 3.75k | { |
289 | 3.75k | if (fieldToRemove == nullptr) |
290 | 0 | return true; |
291 | | |
292 | 3.75k | if (fieldToRemove->m_TextBasedProtocolMessage != this) |
293 | 0 | { |
294 | 0 | PCPP_LOG_ERROR("Field isn't associated with this message"); |
295 | 0 | return false; |
296 | 0 | } |
297 | | |
298 | 3.75k | std::string fieldName = fieldToRemove->getFieldName(); |
299 | | |
300 | | // shorten layer and delete this field |
301 | 3.75k | if (!shortenLayer(fieldToRemove->m_NameOffsetInMessage, fieldToRemove->getFieldSize())) |
302 | 12 | { |
303 | 12 | PCPP_LOG_ERROR("Cannot shorten layer"); |
304 | 12 | return false; |
305 | 12 | } |
306 | | |
307 | | // update offsets of all fields after this field |
308 | 3.74k | HeaderField* curField = fieldToRemove->getNextField(); |
309 | 3.74k | shiftFieldsOffset(curField, 0 - fieldToRemove->getFieldSize()); |
310 | | |
311 | | // update fields link list |
312 | 3.74k | if (fieldToRemove == m_FieldList) |
313 | 3.05k | m_FieldList = m_FieldList->getNextField(); |
314 | 694 | else |
315 | 694 | { |
316 | 694 | curField = m_FieldList; |
317 | 9.78k | while (curField->getNextField() != fieldToRemove) |
318 | 9.09k | curField = curField->getNextField(); |
319 | | |
320 | 694 | curField->setNextField(fieldToRemove->getNextField()); |
321 | 694 | } |
322 | | |
323 | | // re-calculate m_LastField if needed |
324 | 3.74k | if (fieldToRemove == m_LastField) |
325 | 562 | { |
326 | 562 | if (m_FieldList == nullptr) |
327 | 0 | m_LastField = nullptr; |
328 | 562 | else |
329 | 562 | { |
330 | 562 | curField = m_FieldList; |
331 | 8.27k | while (curField->getNextField() != nullptr) |
332 | 7.70k | curField = curField->getNextField(); |
333 | 562 | m_LastField = curField; |
334 | 562 | } |
335 | 562 | } |
336 | | |
337 | | // remove the hash entry for this field |
338 | 3.74k | std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), ::tolower); |
339 | 3.74k | auto range = m_FieldNameToFieldMap.equal_range(fieldName); |
340 | 3.74k | for (std::multimap<std::string, HeaderField*>::iterator iter = range.first; iter != range.second; ++iter) |
341 | 3.74k | { |
342 | 3.74k | if (iter->second == fieldToRemove) |
343 | 3.74k | { |
344 | 3.74k | m_FieldNameToFieldMap.erase(iter); |
345 | 3.74k | break; |
346 | 3.74k | } |
347 | 3.74k | } |
348 | | |
349 | | // finally - delete this field |
350 | 3.74k | delete fieldToRemove; |
351 | | |
352 | 3.74k | return true; |
353 | 3.75k | } |
354 | | |
355 | | bool TextBasedProtocolMessage::isHeaderComplete() const |
356 | 0 | { |
357 | 0 | if (m_LastField == nullptr) |
358 | 0 | return false; |
359 | | |
360 | 0 | return (m_LastField->getFieldName() == PCPP_END_OF_TEXT_BASED_PROTOCOL_HEADER); |
361 | 0 | } |
362 | | |
363 | | void TextBasedProtocolMessage::shiftFieldsOffset(HeaderField* fromField, int numOfBytesToShift) |
364 | 9.55k | { |
365 | 49.2k | while (fromField != nullptr) |
366 | 39.6k | { |
367 | 39.6k | fromField->m_NameOffsetInMessage += numOfBytesToShift; |
368 | 39.6k | if (fromField->m_ValueOffsetInMessage != -1) |
369 | 37.1k | fromField->m_ValueOffsetInMessage += numOfBytesToShift; |
370 | 39.6k | fromField = fromField->getNextField(); |
371 | 39.6k | } |
372 | 9.55k | } |
373 | | |
374 | | HeaderField* TextBasedProtocolMessage::getFieldByName(std::string fieldName, int index) const |
375 | 155k | { |
376 | 155k | std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), ::tolower); |
377 | | |
378 | 155k | auto range = m_FieldNameToFieldMap.equal_range(fieldName); |
379 | 155k | int i = 0; |
380 | 219k | for (std::multimap<std::string, HeaderField*>::const_iterator iter = range.first; iter != range.second; ++iter) |
381 | 202k | { |
382 | 202k | if (i == index) |
383 | 137k | return iter->second; |
384 | | |
385 | 64.5k | i++; |
386 | 64.5k | } |
387 | | |
388 | 17.7k | return nullptr; |
389 | 155k | } |
390 | | |
391 | | int TextBasedProtocolMessage::getFieldCount() const |
392 | 4.34k | { |
393 | 4.34k | int result = 0; |
394 | | |
395 | 4.34k | HeaderField* curField = getFirstField(); |
396 | 56.3k | while (curField != nullptr) |
397 | 51.9k | { |
398 | 51.9k | if (!curField->isEndOfHeader()) |
399 | 50.4k | result++; |
400 | 51.9k | curField = curField->getNextField(); |
401 | 51.9k | } |
402 | | |
403 | 4.34k | return result; |
404 | 4.34k | } |
405 | | |
406 | | void TextBasedProtocolMessage::parseNextLayer() |
407 | 171k | { |
408 | 171k | size_t headerLen = getHeaderLen(); |
409 | 171k | if (m_DataLen <= headerLen) |
410 | 122k | return; |
411 | | |
412 | 49.8k | constructNextLayer<PayloadLayer>(m_Data + headerLen, m_DataLen - headerLen); |
413 | 49.8k | } |
414 | | |
415 | | size_t TextBasedProtocolMessage::getHeaderLen() const |
416 | 388k | { |
417 | 388k | return m_LastField->m_NameOffsetInMessage + m_LastField->m_FieldSize; |
418 | 388k | } |
419 | | |
420 | | void TextBasedProtocolMessage::computeCalculateFields() |
421 | 28.4k | { |
422 | | // nothing to do for now |
423 | 28.4k | } |
424 | | |
425 | | // -------- Class HeaderField ----------------- |
426 | | |
427 | | HeaderField::HeaderField(TextBasedProtocolMessage* TextBasedProtocolMessage, int offsetInMessage, |
428 | | char nameValueSeparator, bool spacesAllowedBetweenNameAndValue) |
429 | 2.02M | : m_NewFieldData(nullptr), m_TextBasedProtocolMessage(TextBasedProtocolMessage), |
430 | 2.02M | m_NameOffsetInMessage(offsetInMessage), m_NextField(nullptr), m_NameValueSeparator(nameValueSeparator), |
431 | 2.02M | m_SpacesAllowedBetweenNameAndValue(spacesAllowedBetweenNameAndValue) |
432 | 2.02M | { |
433 | 2.02M | char* fieldData = reinterpret_cast<char*>(m_TextBasedProtocolMessage->m_Data + m_NameOffsetInMessage); |
434 | 2.02M | char* fieldEndPtr = static_cast<char*>(memchr( |
435 | 2.02M | fieldData, '\n', m_TextBasedProtocolMessage->m_DataLen - static_cast<size_t>(m_NameOffsetInMessage))); |
436 | 2.02M | if (fieldEndPtr == nullptr) |
437 | 96.1k | m_FieldSize = tbp_my_own_strnlen(fieldData, m_TextBasedProtocolMessage->m_DataLen - |
438 | 96.1k | static_cast<size_t>(m_NameOffsetInMessage)); |
439 | 1.92M | else |
440 | 1.92M | m_FieldSize = fieldEndPtr - fieldData + 1; |
441 | | |
442 | 2.02M | if (m_FieldSize == 0 || (*fieldData) == '\r' || (*fieldData) == '\n') |
443 | 218k | { |
444 | 218k | m_FieldNameSize = -1; |
445 | 218k | m_ValueOffsetInMessage = -1; |
446 | 218k | m_FieldValueSize = -1; |
447 | 218k | m_FieldNameSize = -1; |
448 | 218k | m_IsEndOfHeaderField = true; |
449 | 218k | return; |
450 | 218k | } |
451 | 1.80M | else |
452 | 1.80M | m_IsEndOfHeaderField = false; |
453 | | |
454 | 1.80M | char* fieldValuePtr = static_cast<char*>( |
455 | 1.80M | memchr(fieldData, nameValueSeparator, |
456 | 1.80M | m_TextBasedProtocolMessage->m_DataLen - static_cast<size_t>(m_NameOffsetInMessage))); |
457 | | // could not find the position of the separator, meaning field value position is unknown |
458 | 1.80M | if (fieldValuePtr == nullptr || (fieldEndPtr != nullptr && fieldValuePtr >= fieldEndPtr)) |
459 | 390k | { |
460 | 390k | m_ValueOffsetInMessage = -1; |
461 | 390k | m_FieldValueSize = -1; |
462 | 390k | m_FieldNameSize = m_FieldSize; |
463 | 390k | } |
464 | 1.41M | else |
465 | 1.41M | { |
466 | 1.41M | m_FieldNameSize = fieldValuePtr - fieldData; |
467 | | // Header field looks like this: <field_name>[separator]<zero or more spaces><field_Value> |
468 | | // So fieldValuePtr give us the position of the separator. Value offset is the first non-space byte forward |
469 | 1.41M | fieldValuePtr++; |
470 | | |
471 | | // reached the end of the packet and value start offset wasn't found |
472 | 1.41M | if (static_cast<size_t>(fieldValuePtr - reinterpret_cast<char*>(m_TextBasedProtocolMessage->m_Data)) >= |
473 | 1.41M | m_TextBasedProtocolMessage->getDataLen()) |
474 | 1.18k | { |
475 | 1.18k | m_ValueOffsetInMessage = -1; |
476 | 1.18k | m_FieldValueSize = -1; |
477 | 1.18k | return; |
478 | 1.18k | } |
479 | | |
480 | 1.41M | if (spacesAllowedBetweenNameAndValue) |
481 | 1.10M | { |
482 | | // advance fieldValuePtr 1 byte forward while didn't get to end of packet and fieldValuePtr points to a |
483 | | // space char |
484 | 1.10M | while ( |
485 | 2.15M | static_cast<size_t>(fieldValuePtr - reinterpret_cast<char*>(m_TextBasedProtocolMessage->m_Data)) < |
486 | 2.15M | m_TextBasedProtocolMessage->getDataLen() && |
487 | 2.15M | (*fieldValuePtr) == ' ') |
488 | 1.05M | { |
489 | 1.05M | fieldValuePtr++; |
490 | 1.05M | } |
491 | 1.10M | } |
492 | | |
493 | | // reached the end of the packet and value start offset wasn't found |
494 | 1.41M | if (static_cast<size_t>(fieldValuePtr - reinterpret_cast<char*>(m_TextBasedProtocolMessage->m_Data)) >= |
495 | 1.41M | m_TextBasedProtocolMessage->getDataLen()) |
496 | 243 | { |
497 | 243 | m_ValueOffsetInMessage = -1; |
498 | 243 | m_FieldValueSize = -1; |
499 | 243 | } |
500 | 1.41M | else |
501 | 1.41M | { |
502 | 1.41M | m_ValueOffsetInMessage = fieldValuePtr - reinterpret_cast<char*>(m_TextBasedProtocolMessage->m_Data); |
503 | | // couldn't find the end of the field, so assuming the field value length is from m_ValueOffsetInMessage |
504 | | // until the end of the packet |
505 | 1.41M | if (fieldEndPtr == nullptr) |
506 | 26.3k | { |
507 | | // clang-format off |
508 | 26.3k | m_FieldValueSize = reinterpret_cast<char*>(m_TextBasedProtocolMessage->m_Data + m_TextBasedProtocolMessage->getDataLen()) - fieldValuePtr; |
509 | | // clang-format on |
510 | 26.3k | } |
511 | 1.38M | else |
512 | 1.38M | { |
513 | 1.38M | m_FieldValueSize = fieldEndPtr - fieldValuePtr; |
514 | | // if field ends with \r\n, decrease the value length by 1 |
515 | 1.38M | if ((*(--fieldEndPtr)) == '\r') |
516 | 1.26M | m_FieldValueSize--; |
517 | 1.38M | } |
518 | 1.41M | } |
519 | 1.41M | } |
520 | 1.80M | } |
521 | | |
522 | | HeaderField::HeaderField(const std::string& name, const std::string& value, char nameValueSeparator, |
523 | | bool spacesAllowedBetweenNameAndValue) |
524 | 10.1k | { |
525 | 10.1k | m_NameValueSeparator = nameValueSeparator; |
526 | 10.1k | m_SpacesAllowedBetweenNameAndValue = spacesAllowedBetweenNameAndValue; |
527 | 10.1k | initNewField(name, value); |
528 | 10.1k | } |
529 | | |
530 | | void HeaderField::initNewField(const std::string& name, const std::string& value) |
531 | 69.2k | { |
532 | 69.2k | m_TextBasedProtocolMessage = nullptr; |
533 | 69.2k | m_NameOffsetInMessage = 0; |
534 | 69.2k | m_NextField = nullptr; |
535 | | |
536 | | // first building the name-value separator |
537 | 69.2k | std::string nameValueSeparation(1, m_NameValueSeparator); |
538 | 69.2k | if (m_SpacesAllowedBetweenNameAndValue) |
539 | 0 | nameValueSeparation += " "; |
540 | | |
541 | | // Field size is: name_length + separator_len + value_length + '\r\n' |
542 | 69.2k | if (name != PCPP_END_OF_TEXT_BASED_PROTOCOL_HEADER) |
543 | 67.5k | m_FieldSize = name.length() + nameValueSeparation.length() + value.length() + 2; |
544 | 1.67k | else |
545 | | // Field is \r\n (2B) |
546 | 1.67k | m_FieldSize = 2; |
547 | | |
548 | 69.2k | m_NewFieldData = new uint8_t[m_FieldSize]; |
549 | 69.2k | std::string fieldData; |
550 | | |
551 | 69.2k | if (name != PCPP_END_OF_TEXT_BASED_PROTOCOL_HEADER) |
552 | 67.5k | fieldData = name + nameValueSeparation + value + "\r\n"; |
553 | 1.67k | else |
554 | 1.67k | fieldData = "\r\n"; |
555 | | |
556 | | // copy field data to m_NewFieldData |
557 | 69.2k | memcpy(m_NewFieldData, fieldData.c_str(), m_FieldSize); |
558 | | |
559 | | // calculate value offset |
560 | 69.2k | if (name != PCPP_END_OF_TEXT_BASED_PROTOCOL_HEADER) |
561 | 67.5k | m_ValueOffsetInMessage = name.length() + nameValueSeparation.length(); |
562 | 1.67k | else |
563 | 1.67k | m_ValueOffsetInMessage = 0; |
564 | 69.2k | m_FieldNameSize = name.length(); |
565 | 69.2k | m_FieldValueSize = value.length(); |
566 | | |
567 | 69.2k | if (name != PCPP_END_OF_TEXT_BASED_PROTOCOL_HEADER) |
568 | 67.5k | m_IsEndOfHeaderField = false; |
569 | 1.67k | else |
570 | 1.67k | m_IsEndOfHeaderField = true; |
571 | 69.2k | } |
572 | | |
573 | | HeaderField::~HeaderField() |
574 | 2.09M | { |
575 | 2.09M | if (m_NewFieldData != nullptr) |
576 | 12.8k | delete[] m_NewFieldData; |
577 | 2.09M | } |
578 | | |
579 | | HeaderField::HeaderField(const HeaderField& other) |
580 | 59.0k | : m_NameValueSeparator('\0'), m_SpacesAllowedBetweenNameAndValue(false) |
581 | 59.0k | { |
582 | 59.0k | m_NameValueSeparator = other.m_NameValueSeparator; |
583 | 59.0k | m_SpacesAllowedBetweenNameAndValue = other.m_SpacesAllowedBetweenNameAndValue; |
584 | 59.0k | initNewField(other.getFieldName(), other.getFieldValue()); |
585 | 59.0k | } |
586 | | |
587 | | HeaderField& HeaderField::operator=(const HeaderField& other) |
588 | 0 | { |
589 | 0 | m_NameValueSeparator = other.m_NameValueSeparator; |
590 | 0 | m_SpacesAllowedBetweenNameAndValue = other.m_SpacesAllowedBetweenNameAndValue; |
591 | 0 | if (m_NewFieldData != nullptr) |
592 | 0 | delete[] m_NewFieldData; |
593 | 0 | initNewField(other.getFieldName(), other.getFieldValue()); |
594 | |
|
595 | 0 | return (*this); |
596 | 0 | } |
597 | | |
598 | | char* HeaderField::getData() const |
599 | 2.10M | { |
600 | 2.10M | if (m_TextBasedProtocolMessage == nullptr) |
601 | 14.1k | return reinterpret_cast<char*>(m_NewFieldData); |
602 | 2.09M | else |
603 | 2.09M | return reinterpret_cast<char*>(m_TextBasedProtocolMessage->m_Data); |
604 | 2.10M | } |
605 | | |
606 | | void HeaderField::setNextField(HeaderField* nextField) |
607 | 1.79M | { |
608 | 1.79M | m_NextField = nextField; |
609 | 1.79M | } |
610 | | |
611 | | HeaderField* HeaderField::getNextField() const |
612 | 2.49M | { |
613 | 2.49M | return m_NextField; |
614 | 2.49M | } |
615 | | |
616 | | std::string HeaderField::getFieldName() const |
617 | 2.12M | { |
618 | 2.12M | std::string result; |
619 | | |
620 | 2.12M | if (m_FieldNameSize != static_cast<size_t>(-1)) |
621 | 1.93M | result.assign((getData() + m_NameOffsetInMessage), m_FieldNameSize); |
622 | | |
623 | 2.12M | return result; |
624 | 2.12M | } |
625 | | |
626 | | std::string HeaderField::getFieldValue() const |
627 | 189k | { |
628 | 189k | std::string result; |
629 | 189k | if (m_ValueOffsetInMessage != -1) |
630 | 169k | result.assign((getData() + m_ValueOffsetInMessage), m_FieldValueSize); |
631 | 189k | return result; |
632 | 189k | } |
633 | | |
634 | | bool HeaderField::setFieldValue(const std::string& newValue) |
635 | 5.13k | { |
636 | | // Field isn't linked with any message yet |
637 | 5.13k | if (m_TextBasedProtocolMessage == nullptr) |
638 | 0 | { |
639 | 0 | std::string name = getFieldName(); |
640 | 0 | delete[] m_NewFieldData; |
641 | 0 | initNewField(name, newValue); |
642 | 0 | return true; |
643 | 0 | } |
644 | | |
645 | 5.13k | std::string curValue = getFieldValue(); |
646 | 5.13k | int lengthDifference = newValue.length() - curValue.length(); |
647 | | // new value is longer than current value |
648 | 5.13k | if (lengthDifference > 0) |
649 | 711 | { |
650 | 711 | if (!m_TextBasedProtocolMessage->extendLayer(m_ValueOffsetInMessage, lengthDifference)) |
651 | 0 | { |
652 | 0 | PCPP_LOG_ERROR("Could not extend layer"); |
653 | 0 | return false; |
654 | 0 | } |
655 | 711 | } |
656 | | // new value is shorter than current value |
657 | 4.42k | else if (lengthDifference < 0) |
658 | 657 | { |
659 | 657 | if (!m_TextBasedProtocolMessage->shortenLayer(m_ValueOffsetInMessage, 0 - lengthDifference)) |
660 | 0 | { |
661 | 0 | PCPP_LOG_ERROR("Could not shorten layer"); |
662 | 0 | return false; |
663 | 0 | } |
664 | 657 | } |
665 | | |
666 | 5.13k | if (lengthDifference != 0) |
667 | 1.36k | m_TextBasedProtocolMessage->shiftFieldsOffset(getNextField(), lengthDifference); |
668 | | |
669 | | // update sizes |
670 | 5.13k | m_FieldValueSize += lengthDifference; |
671 | 5.13k | m_FieldSize += lengthDifference; |
672 | | |
673 | | // write new value to field data |
674 | 5.13k | memcpy(getData() + m_ValueOffsetInMessage, newValue.c_str(), newValue.length()); |
675 | | |
676 | 5.13k | return true; |
677 | 5.13k | } |
678 | | |
679 | | void HeaderField::attachToTextBasedProtocolMessage(TextBasedProtocolMessage* message, int fieldOffsetInMessage) |
680 | 56.4k | { |
681 | 56.4k | if (m_TextBasedProtocolMessage != nullptr && m_TextBasedProtocolMessage != message) |
682 | 0 | { |
683 | 0 | PCPP_LOG_ERROR("Header field already associated with another message"); |
684 | 0 | return; |
685 | 0 | } |
686 | | |
687 | 56.4k | if (m_NewFieldData == nullptr) |
688 | 0 | { |
689 | 0 | PCPP_LOG_ERROR("Header field doesn't have new field data"); |
690 | 0 | return; |
691 | 0 | } |
692 | | |
693 | 56.4k | delete[] m_NewFieldData; |
694 | 56.4k | m_NewFieldData = nullptr; |
695 | 56.4k | m_TextBasedProtocolMessage = message; |
696 | | |
697 | 56.4k | int valueAndNameDifference = m_ValueOffsetInMessage - m_NameOffsetInMessage; |
698 | 56.4k | m_NameOffsetInMessage = fieldOffsetInMessage; |
699 | 56.4k | m_ValueOffsetInMessage = m_NameOffsetInMessage + valueAndNameDifference; |
700 | 56.4k | } |
701 | | |
702 | | } // namespace pcpp |