Coverage Report

Created: 2026-02-26 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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