Coverage Report

Created: 2026-03-31 07:53

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