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
60.9k
  {
14
60.9k
    if (s == nullptr || maxlen == 0)
15
21.8k
      return 0;
16
17
39.0k
    size_t i = 0;
18
1.20M
    for (; (i < maxlen) && s[i]; ++i)
19
1.16M
      ;
20
39.0k
    return i;
21
60.9k
  }
22
23
  // -------- Class TextBasedProtocolMessage -----------------
24
25
  TextBasedProtocolMessage::TextBasedProtocolMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet,
26
                                                     ProtocolType protocol)
27
142k
      : Layer(data, dataLen, prevLayer, packet, protocol), m_FieldList(nullptr), m_LastField(nullptr),
28
142k
        m_FieldsOffset(0)
29
142k
  {}
30
31
898
  TextBasedProtocolMessage::TextBasedProtocolMessage(const TextBasedProtocolMessage& other) : Layer(other)
32
898
  {
33
898
    copyDataFrom(other);
34
898
  }
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
898
  {
54
    // copy field list
55
898
    if (other.m_FieldList != nullptr)
56
898
    {
57
898
      m_FieldList = new HeaderField(*(other.m_FieldList));
58
898
      HeaderField* curField = m_FieldList;
59
898
      curField->attachToTextBasedProtocolMessage(this, other.m_FieldList->m_NameOffsetInMessage);
60
898
      HeaderField* curOtherField = other.m_FieldList;
61
14.2k
      while (curOtherField->getNextField() != nullptr)
62
13.3k
      {
63
13.3k
        HeaderField* newField = new HeaderField(*(curOtherField->getNextField()));
64
13.3k
        newField->attachToTextBasedProtocolMessage(this, curOtherField->getNextField()->m_NameOffsetInMessage);
65
13.3k
        curField->setNextField(newField);
66
13.3k
        curField = curField->getNextField();
67
13.3k
        curOtherField = curOtherField->getNextField();
68
13.3k
      }
69
70
898
      m_LastField = curField;
71
898
    }
72
0
    else
73
0
    {
74
0
      m_FieldList = nullptr;
75
0
      m_LastField = nullptr;
76
0
    }
77
78
898
    m_FieldsOffset = other.m_FieldsOffset;
79
80
    // copy map
81
15.1k
    for (HeaderField* field = m_FieldList; field != nullptr; field = field->getNextField())
82
14.2k
    {
83
14.2k
      m_FieldNameToFieldMap.insert(std::pair<std::string, HeaderField*>(field->getFieldName(), field));
84
14.2k
    }
85
898
  }
86
87
  void TextBasedProtocolMessage::parseFields()
88
142k
  {
89
142k
    char nameValueSeparator = getHeaderFieldNameValueSeparator();
90
142k
    bool spacesAllowedBetweenNameAndValue = spacesAllowedBetweenHeaderFieldNameAndValue();
91
92
142k
    HeaderField* firstField =
93
142k
        new HeaderField(this, m_FieldsOffset, nameValueSeparator, spacesAllowedBetweenNameAndValue);
94
142k
    PCPP_LOG_DEBUG("Added new field: name='" << firstField->getFieldName()
95
142k
                                             << "'; offset in packet=" << firstField->m_NameOffsetInMessage
96
142k
                                             << "; length=" << firstField->getFieldSize());
97
142k
    PCPP_LOG_DEBUG("     Field value = " << firstField->getFieldValue());
98
99
142k
    if (m_FieldList == nullptr)
100
142k
      m_FieldList = firstField;
101
0
    else
102
0
      m_FieldList->setNextField(firstField);
103
104
142k
    std::string fieldName = firstField->getFieldName();
105
142k
    std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), ::tolower);
106
142k
    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
142k
    HeaderField* curField = m_FieldList;
110
142k
    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
925k
    while (!curField->isEndOfHeader() && curOffset + curField->getFieldSize() < m_DataLen)
115
795k
    {
116
795k
      curOffset += curField->getFieldSize();
117
795k
      HeaderField* newField =
118
795k
          new HeaderField(this, curOffset, nameValueSeparator, spacesAllowedBetweenNameAndValue);
119
795k
      if (newField->getFieldSize() > 0)
120
782k
      {
121
782k
        PCPP_LOG_DEBUG("Added new field: name='" << newField->getFieldName()
122
782k
                                                 << "'; offset in packet=" << newField->m_NameOffsetInMessage
123
782k
                                                 << "; length=" << newField->getFieldSize());
124
782k
        PCPP_LOG_DEBUG("     Field value = " << newField->getFieldValue());
125
782k
        curField->setNextField(newField);
126
782k
        curField = newField;
127
782k
        fieldName = newField->getFieldName();
128
782k
        std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), ::tolower);
129
782k
        m_FieldNameToFieldMap.insert(std::pair<std::string, HeaderField*>(fieldName, newField));
130
782k
      }
131
12.8k
      else
132
12.8k
      {
133
12.8k
        delete newField;
134
12.8k
        break;
135
12.8k
      }
136
795k
    }
137
138
142k
    m_LastField = curField;
139
142k
  }
140
141
  TextBasedProtocolMessage::~TextBasedProtocolMessage()
142
143k
  {
143
1.08M
    while (m_FieldList != nullptr)
144
939k
    {
145
939k
      HeaderField* temp = m_FieldList;
146
939k
      m_FieldList = m_FieldList->getNextField();
147
939k
      delete temp;
148
939k
    }
149
143k
  }
150
151
  HeaderField* TextBasedProtocolMessage::addField(const std::string& fieldName, const std::string& fieldValue)
152
2.01k
  {
153
2.01k
    HeaderField newField(fieldName, fieldValue, getHeaderFieldNameValueSeparator(),
154
2.01k
                         spacesAllowedBetweenHeaderFieldNameAndValue());
155
2.01k
    return addField(newField);
156
2.01k
  }
157
158
  HeaderField* TextBasedProtocolMessage::addField(const HeaderField& newField)
159
2.01k
  {
160
2.01k
    return insertField(m_LastField, newField);
161
2.01k
  }
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
2.01k
  {
196
2.01k
    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
2.01k
    if (prevField != nullptr && prevField->getFieldName() == PCPP_END_OF_TEXT_BASED_PROTOCOL_HEADER)
203
250
    {
204
250
      PCPP_LOG_ERROR("Cannot add a field after end of header");
205
250
      return nullptr;
206
250
    }
207
208
1.76k
    HeaderField* newFieldToAdd = new HeaderField(newField);
209
210
1.76k
    int newFieldOffset = m_FieldsOffset;
211
1.76k
    if (prevField != nullptr)
212
1.76k
      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
1.76k
    if (!extendLayer(newFieldOffset, newFieldToAdd->getFieldSize()))
216
1.11k
    {
217
1.11k
      PCPP_LOG_ERROR("Cannot extend layer to insert the header");
218
1.11k
      delete newFieldToAdd;
219
1.11k
      return nullptr;
220
1.11k
    }
221
222
648
    HeaderField* curField = m_FieldList;
223
648
    if (prevField != nullptr)
224
648
      curField = prevField->getNextField();
225
226
    // go over all fields after prevField and update their offsets
227
648
    shiftFieldsOffset(curField, newFieldToAdd->getFieldSize());
228
229
    // copy new field data to message
230
648
    memcpy(m_Data + newFieldOffset, newFieldToAdd->m_NewFieldData, newFieldToAdd->getFieldSize());
231
232
    // attach new field to message
233
648
    newFieldToAdd->attachToTextBasedProtocolMessage(this, newFieldOffset);
234
235
    // insert field into fields link list
236
648
    if (prevField == nullptr)
237
0
    {
238
0
      newFieldToAdd->setNextField(m_FieldList);
239
0
      m_FieldList = newFieldToAdd;
240
0
    }
241
648
    else
242
648
    {
243
648
      newFieldToAdd->setNextField(prevField->getNextField());
244
648
      prevField->setNextField(newFieldToAdd);
245
648
    }
246
247
    // if newField is the last field, update m_LastField
248
648
    if (newFieldToAdd->getNextField() == nullptr)
249
648
      m_LastField = newFieldToAdd;
250
251
    // insert the new field into name to field map
252
648
    std::string fieldName = newFieldToAdd->getFieldName();
253
648
    std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), ::tolower);
254
648
    m_FieldNameToFieldMap.insert(std::pair<std::string, HeaderField*>(fieldName, newFieldToAdd));
255
256
648
    return newFieldToAdd;
257
1.76k
  }
258
259
  bool TextBasedProtocolMessage::removeField(std::string fieldName, int index)
260
898
  {
261
898
    std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), ::tolower);
262
263
898
    HeaderField* fieldToRemove = nullptr;
264
265
898
    auto range = m_FieldNameToFieldMap.equal_range(fieldName);
266
898
    int i = 0;
267
898
    for (std::multimap<std::string, HeaderField*>::iterator iter = range.first; iter != range.second; ++iter)
268
475
    {
269
475
      if (i == index)
270
475
      {
271
475
        fieldToRemove = iter->second;
272
475
        break;
273
475
      }
274
275
0
      i++;
276
0
    }
277
278
898
    if (fieldToRemove != nullptr)
279
475
      return removeField(fieldToRemove);
280
423
    else
281
423
    {
282
423
      PCPP_LOG_ERROR("Cannot find field '" << fieldName << "'");
283
423
      return false;
284
423
    }
285
898
  }
286
287
  bool TextBasedProtocolMessage::removeField(HeaderField* fieldToRemove)
288
475
  {
289
475
    if (fieldToRemove == nullptr)
290
0
      return true;
291
292
475
    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
475
    std::string fieldName = fieldToRemove->getFieldName();
299
300
    // shorten layer and delete this field
301
475
    if (!shortenLayer(fieldToRemove->m_NameOffsetInMessage, fieldToRemove->getFieldSize()))
302
11
    {
303
11
      PCPP_LOG_ERROR("Cannot shorten layer");
304
11
      return false;
305
11
    }
306
307
    // update offsets of all fields after this field
308
464
    HeaderField* curField = fieldToRemove->getNextField();
309
464
    shiftFieldsOffset(curField, 0 - fieldToRemove->getFieldSize());
310
311
    // update fields link list
312
464
    if (fieldToRemove == m_FieldList)
313
403
      m_FieldList = m_FieldList->getNextField();
314
61
    else
315
61
    {
316
61
      curField = m_FieldList;
317
996
      while (curField->getNextField() != fieldToRemove)
318
935
        curField = curField->getNextField();
319
320
61
      curField->setNextField(fieldToRemove->getNextField());
321
61
    }
322
323
    // re-calculate m_LastField if needed
324
464
    if (fieldToRemove == m_LastField)
325
47
    {
326
47
      if (m_FieldList == nullptr)
327
0
        m_LastField = nullptr;
328
47
      else
329
47
      {
330
47
        curField = m_FieldList;
331
928
        while (curField->getNextField() != nullptr)
332
881
          curField = curField->getNextField();
333
47
        m_LastField = curField;
334
47
      }
335
47
    }
336
337
    // remove the hash entry for this field
338
464
    std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), ::tolower);
339
464
    auto range = m_FieldNameToFieldMap.equal_range(fieldName);
340
464
    for (std::multimap<std::string, HeaderField*>::iterator iter = range.first; iter != range.second; ++iter)
341
464
    {
342
464
      if (iter->second == fieldToRemove)
343
464
      {
344
464
        m_FieldNameToFieldMap.erase(iter);
345
464
        break;
346
464
      }
347
464
    }
348
349
    // finally - delete this field
350
464
    delete fieldToRemove;
351
352
464
    return true;
353
475
  }
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
1.62k
  {
365
9.09k
    while (fromField != nullptr)
366
7.47k
    {
367
7.47k
      fromField->m_NameOffsetInMessage += numOfBytesToShift;
368
7.47k
      if (fromField->m_ValueOffsetInMessage != -1)
369
6.27k
        fromField->m_ValueOffsetInMessage += numOfBytesToShift;
370
7.47k
      fromField = fromField->getNextField();
371
7.47k
    }
372
1.62k
  }
373
374
  HeaderField* TextBasedProtocolMessage::getFieldByName(std::string fieldName, int index) const
375
32.4k
  {
376
32.4k
    std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), ::tolower);
377
378
32.4k
    auto range = m_FieldNameToFieldMap.equal_range(fieldName);
379
32.4k
    int i = 0;
380
94.4k
    for (std::multimap<std::string, HeaderField*>::const_iterator iter = range.first; iter != range.second; ++iter)
381
86.3k
    {
382
86.3k
      if (i == index)
383
24.3k
        return iter->second;
384
385
62.0k
      i++;
386
62.0k
    }
387
388
8.10k
    return nullptr;
389
32.4k
  }
390
391
  int TextBasedProtocolMessage::getFieldCount() const
392
898
  {
393
898
    int result = 0;
394
395
898
    HeaderField* curField = getFirstField();
396
15.1k
    while (curField != nullptr)
397
14.2k
    {
398
14.2k
      if (!curField->isEndOfHeader())
399
14.1k
        result++;
400
14.2k
      curField = curField->getNextField();
401
14.2k
    }
402
403
898
    return result;
404
898
  }
405
406
  void TextBasedProtocolMessage::parseNextLayer()
407
115k
  {
408
115k
    size_t headerLen = getHeaderLen();
409
115k
    if (m_DataLen <= headerLen)
410
84.3k
      return;
411
412
30.9k
    constructNextLayer<PayloadLayer>(m_Data + headerLen, m_DataLen - headerLen);
413
30.9k
  }
414
415
  size_t TextBasedProtocolMessage::getHeaderLen() const
416
184k
  {
417
184k
    return m_LastField->m_NameOffsetInMessage + m_LastField->m_FieldSize;
418
184k
  }
419
420
  void TextBasedProtocolMessage::computeCalculateFields()
421
21.3k
  {
422
    // nothing to do for now
423
21.3k
  }
424
425
  // -------- Class HeaderField -----------------
426
427
  HeaderField::HeaderField(TextBasedProtocolMessage* TextBasedProtocolMessage, int offsetInMessage,
428
                           char nameValueSeparator, bool spacesAllowedBetweenNameAndValue)
429
937k
      : m_NewFieldData(nullptr), m_TextBasedProtocolMessage(TextBasedProtocolMessage),
430
937k
        m_NameOffsetInMessage(offsetInMessage), m_NextField(nullptr), m_NameValueSeparator(nameValueSeparator),
431
937k
        m_SpacesAllowedBetweenNameAndValue(spacesAllowedBetweenNameAndValue)
432
937k
  {
433
937k
    char* fieldData = reinterpret_cast<char*>(m_TextBasedProtocolMessage->m_Data + m_NameOffsetInMessage);
434
937k
    char* fieldEndPtr = static_cast<char*>(memchr(
435
937k
        fieldData, '\n', m_TextBasedProtocolMessage->m_DataLen - static_cast<size_t>(m_NameOffsetInMessage)));
436
937k
    if (fieldEndPtr == nullptr)
437
60.9k
      m_FieldSize = tbp_my_own_strnlen(fieldData, m_TextBasedProtocolMessage->m_DataLen -
438
60.9k
                                                      static_cast<size_t>(m_NameOffsetInMessage));
439
877k
    else
440
877k
      m_FieldSize = fieldEndPtr - fieldData + 1;
441
442
937k
    if (m_FieldSize == 0 || (*fieldData) == '\r' || (*fieldData) == '\n')
443
125k
    {
444
125k
      m_FieldNameSize = -1;
445
125k
      m_ValueOffsetInMessage = -1;
446
125k
      m_FieldValueSize = -1;
447
125k
      m_FieldNameSize = -1;
448
125k
      m_IsEndOfHeaderField = true;
449
125k
      return;
450
125k
    }
451
812k
    else
452
812k
      m_IsEndOfHeaderField = false;
453
454
812k
    char* fieldValuePtr = static_cast<char*>(
455
812k
        memchr(fieldData, nameValueSeparator,
456
812k
               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
812k
    if (fieldValuePtr == nullptr || (fieldEndPtr != nullptr && fieldValuePtr >= fieldEndPtr))
459
218k
    {
460
218k
      m_ValueOffsetInMessage = -1;
461
218k
      m_FieldValueSize = -1;
462
218k
      m_FieldNameSize = m_FieldSize;
463
218k
    }
464
594k
    else
465
594k
    {
466
594k
      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
594k
      fieldValuePtr++;
470
471
      // reached the end of the packet and value start offset wasn't found
472
594k
      if (static_cast<size_t>(fieldValuePtr - reinterpret_cast<char*>(m_TextBasedProtocolMessage->m_Data)) >=
473
594k
          m_TextBasedProtocolMessage->getDataLen())
474
559
      {
475
559
        m_ValueOffsetInMessage = -1;
476
559
        m_FieldValueSize = -1;
477
559
        return;
478
559
      }
479
480
593k
      if (spacesAllowedBetweenNameAndValue)
481
541k
      {
482
        // advance fieldValuePtr 1 byte forward while didn't get to end of packet and fieldValuePtr points to a
483
        // space char
484
541k
        while (
485
1.04M
            static_cast<size_t>(fieldValuePtr - reinterpret_cast<char*>(m_TextBasedProtocolMessage->m_Data)) <
486
1.04M
                m_TextBasedProtocolMessage->getDataLen() &&
487
1.04M
            (*fieldValuePtr) == ' ')
488
500k
        {
489
500k
          fieldValuePtr++;
490
500k
        }
491
541k
      }
492
493
      // reached the end of the packet and value start offset wasn't found
494
593k
      if (static_cast<size_t>(fieldValuePtr - reinterpret_cast<char*>(m_TextBasedProtocolMessage->m_Data)) >=
495
593k
          m_TextBasedProtocolMessage->getDataLen())
496
211
      {
497
211
        m_ValueOffsetInMessage = -1;
498
211
        m_FieldValueSize = -1;
499
211
      }
500
593k
      else
501
593k
      {
502
593k
        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
593k
        if (fieldEndPtr == nullptr)
506
11.5k
        {
507
          // clang-format off
508
11.5k
          m_FieldValueSize = reinterpret_cast<char*>(m_TextBasedProtocolMessage->m_Data + m_TextBasedProtocolMessage->getDataLen()) - fieldValuePtr;
509
          // clang-format on
510
11.5k
        }
511
582k
        else
512
582k
        {
513
582k
          m_FieldValueSize = fieldEndPtr - fieldValuePtr;
514
          // if field ends with \r\n, decrease the value length by 1
515
582k
          if ((*(--fieldEndPtr)) == '\r')
516
528k
            m_FieldValueSize--;
517
582k
        }
518
593k
      }
519
593k
    }
520
812k
  }
521
522
  HeaderField::HeaderField(const std::string& name, const std::string& value, char nameValueSeparator,
523
                           bool spacesAllowedBetweenNameAndValue)
524
2.01k
  {
525
2.01k
    m_NameValueSeparator = nameValueSeparator;
526
2.01k
    m_SpacesAllowedBetweenNameAndValue = spacesAllowedBetweenNameAndValue;
527
2.01k
    initNewField(name, value);
528
2.01k
  }
529
530
  void HeaderField::initNewField(const std::string& name, const std::string& value)
531
18.0k
  {
532
18.0k
    m_TextBasedProtocolMessage = nullptr;
533
18.0k
    m_NameOffsetInMessage = 0;
534
18.0k
    m_NextField = nullptr;
535
536
    // first building the name-value separator
537
18.0k
    std::string nameValueSeparation(1, m_NameValueSeparator);
538
18.0k
    if (m_SpacesAllowedBetweenNameAndValue)
539
0
      nameValueSeparation += " ";
540
541
    // Field size is: name_length + separator_len + value_length + '\r\n'
542
18.0k
    if (name != PCPP_END_OF_TEXT_BASED_PROTOCOL_HEADER)
543
17.8k
      m_FieldSize = name.length() + nameValueSeparation.length() + value.length() + 2;
544
201
    else
545
      // Field is \r\n (2B)
546
201
      m_FieldSize = 2;
547
548
18.0k
    m_NewFieldData = new uint8_t[m_FieldSize];
549
18.0k
    std::string fieldData;
550
551
18.0k
    if (name != PCPP_END_OF_TEXT_BASED_PROTOCOL_HEADER)
552
17.8k
      fieldData = name + nameValueSeparation + value + "\r\n";
553
201
    else
554
201
      fieldData = "\r\n";
555
556
    // copy field data to m_NewFieldData
557
18.0k
    memcpy(m_NewFieldData, fieldData.c_str(), m_FieldSize);
558
559
    // calculate value offset
560
18.0k
    if (name != PCPP_END_OF_TEXT_BASED_PROTOCOL_HEADER)
561
17.8k
      m_ValueOffsetInMessage = name.length() + nameValueSeparation.length();
562
201
    else
563
201
      m_ValueOffsetInMessage = 0;
564
18.0k
    m_FieldNameSize = name.length();
565
18.0k
    m_FieldValueSize = value.length();
566
567
18.0k
    if (name != PCPP_END_OF_TEXT_BASED_PROTOCOL_HEADER)
568
17.8k
      m_IsEndOfHeaderField = false;
569
201
    else
570
201
      m_IsEndOfHeaderField = true;
571
18.0k
  }
572
573
  HeaderField::~HeaderField()
574
955k
  {
575
955k
    if (m_NewFieldData != nullptr)
576
3.12k
      delete[] m_NewFieldData;
577
955k
  }
578
579
  HeaderField::HeaderField(const HeaderField& other)
580
15.9k
      : m_NameValueSeparator('\0'), m_SpacesAllowedBetweenNameAndValue(false)
581
15.9k
  {
582
15.9k
    m_NameValueSeparator = other.m_NameValueSeparator;
583
15.9k
    m_SpacesAllowedBetweenNameAndValue = other.m_SpacesAllowedBetweenNameAndValue;
584
15.9k
    initNewField(other.getFieldName(), other.getFieldValue());
585
15.9k
  }
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
878k
  {
600
878k
    if (m_TextBasedProtocolMessage == nullptr)
601
3.52k
      return reinterpret_cast<char*>(m_NewFieldData);
602
875k
    else
603
875k
      return reinterpret_cast<char*>(m_TextBasedProtocolMessage->m_Data);
604
878k
  }
605
606
  void HeaderField::setNextField(HeaderField* nextField)
607
797k
  {
608
797k
    m_NextField = nextField;
609
797k
  }
610
611
  HeaderField* HeaderField::getNextField() const
612
1.05M
  {
613
1.05M
    return m_NextField;
614
1.05M
  }
615
616
  std::string HeaderField::getFieldName() const
617
958k
  {
618
958k
    std::string result;
619
620
958k
    if (m_FieldNameSize != static_cast<size_t>(-1))
621
845k
      result.assign((getData() + m_NameOffsetInMessage), m_FieldNameSize);
622
623
958k
    return result;
624
958k
  }
625
626
  std::string HeaderField::getFieldValue() const
627
38.1k
  {
628
38.1k
    std::string result;
629
38.1k
    if (m_ValueOffsetInMessage != -1)
630
31.9k
      result.assign((getData() + m_ValueOffsetInMessage), m_FieldValueSize);
631
38.1k
    return result;
632
38.1k
  }
633
634
  bool HeaderField::setFieldValue(const std::string& newValue)
635
945
  {
636
    // Field isn't linked with any message yet
637
945
    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
945
    std::string curValue = getFieldValue();
646
945
    int lengthDifference = newValue.length() - curValue.length();
647
    // new value is longer than current value
648
945
    if (lengthDifference > 0)
649
85
    {
650
85
      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
85
    }
656
    // new value is shorter than current value
657
860
    else if (lengthDifference < 0)
658
426
    {
659
426
      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
426
    }
665
666
945
    if (lengthDifference != 0)
667
511
      m_TextBasedProtocolMessage->shiftFieldsOffset(getNextField(), lengthDifference);
668
669
    // update sizes
670
945
    m_FieldValueSize += lengthDifference;
671
945
    m_FieldSize += lengthDifference;
672
673
    // write new value to field data
674
945
    memcpy(getData() + m_ValueOffsetInMessage, newValue.c_str(), newValue.length());
675
676
945
    return true;
677
945
  }
678
679
  void HeaderField::attachToTextBasedProtocolMessage(TextBasedProtocolMessage* message, int fieldOffsetInMessage)
680
14.8k
  {
681
14.8k
    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
14.8k
    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
14.8k
    delete[] m_NewFieldData;
694
14.8k
    m_NewFieldData = nullptr;
695
14.8k
    m_TextBasedProtocolMessage = message;
696
697
14.8k
    int valueAndNameDifference = m_ValueOffsetInMessage - m_NameOffsetInMessage;
698
14.8k
    m_NameOffsetInMessage = fieldOffsetInMessage;
699
14.8k
    m_ValueOffsetInMessage = m_NameOffsetInMessage + valueAndNameDifference;
700
14.8k
  }
701
702
}  // namespace pcpp