Coverage Report

Created: 2026-03-07 06:49

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