Coverage Report

Created: 2023-01-17 06:15

/src/PcapPlusPlus/Packet++/header/TextBasedProtocol.h
Line
Count
Source (jump to first uncovered line)
1
#ifndef PACKETPP_TEXT_BASED_PROTOCOL_LAYER
2
#define PACKETPP_TEXT_BASED_PROTOCOL_LAYER
3
4
#include <map>
5
#include "Layer.h"
6
7
/// @file
8
9
namespace pcpp
10
{
11
12
/** End of header */
13
0
#define PCPP_END_OF_TEXT_BASED_PROTOCOL_HEADER ""
14
15
class TextBasedProtocolMessage;
16
17
18
// -------- Class HeaderField -----------------
19
20
21
/**
22
 * @class HeaderField
23
 * A wrapper class for each text-based-protocol header field, e.g "Host", "Cookie", "Content-Length", "Via", "Call-ID", etc.
24
 * Each field contains a name (e.g "Host") and a value (e.g "www.wikipedia.org"). The user can get and set both of them through dedicated methods.
25
 * The separator between header fields is either CRLF ("\r\n\") or LF ("\n") in more rare cases, which means every HeaderField instance is
26
 * responsible for wrapping and parsing a header field from the previous CRLF (not inclusive) until the next CRLF/LF (inclusive)
27
 * A special case is with the end of a header, meaning 2 consecutive CRLFs ("\r\n\r\n") or consecutive LFs ("\n\n"). PcapPlusPlus treats the first
28
 * CRLF/LF as part of the last field in the header, and the second CRLF is an HeaderField instance of its own which name and values are an empty string ("")
29
 * or pcpp::PCPP_END_OF_TEXT_BASED_PROTOCOL_HEADER
30
 */
31
class HeaderField
32
{
33
  friend class TextBasedProtocolMessage;
34
public:
35
36
  ~HeaderField();
37
38
  /**
39
   * A copy constructor that creates a new instance out of an existing HeaderField instance. The copied instance will not have shared
40
   * resources with the original instance, meaning all members and properties are copied
41
   * @param[in] other The original instance to copy from
42
   */
43
  HeaderField(const HeaderField& other);
44
45
  /**
46
   * Assignment operator for this class. This method copies the data from the other instance and will not share any resources with it.
47
   * Also, if the instance already contains data it will be deleted or zeroed
48
   * @param[in] other The instance to assign from
49
   * @return A reference to the assignee
50
   */
51
  HeaderField& operator=(const HeaderField& other);
52
53
  /**
54
   * @return The field length in bytes, meaning count of all characters from the previous CRLF (not inclusive) until the next CRLF (inclusive)
55
   * For example: the field "Host: www.wikipedia.org\r\n" will have the length of 25
56
   */
57
269k
  size_t getFieldSize() const { return m_FieldSize; }
58
59
  /**
60
   * @return The field name as string. Notice the return data is copied data, so changing it won't change the packet data
61
   */
62
  std::string getFieldName() const;
63
64
  /**
65
   * @return The field value as string. Notice the return data is copied data, so changing it won't change the packet data
66
   */
67
  std::string getFieldValue() const;
68
69
  /**
70
   * A setter for field value
71
   * @param[in] newValue The new value to set to the field. Old value will be deleted
72
   * @return True if setting the value was completed successfully, false otherwise
73
   */
74
  bool setFieldValue(std::string newValue);
75
76
  /**
77
   * Get an indication whether the field is a field that ends the header (meaning contain only CRLF - see class explanation)
78
   * @return True if this is a end-of-header field, false otherwise
79
   */
80
128k
  bool isEndOfHeader() const { return m_IsEndOfHeaderField; }
81
82
private:
83
  HeaderField(std::string name, std::string value, char nameValueSeparator, bool spacesAllowedBetweenNameAndValue);
84
  HeaderField(TextBasedProtocolMessage* TextBasedProtocolMessage, int offsetInMessage, char nameValueSeparator, bool spacesAllowedBetweenNameAndValue);
85
86
  char* getData() const;
87
  void setNextField(HeaderField* nextField);
88
  HeaderField *getNextField() const;
89
  void initNewField(std::string name, std::string value);
90
  void attachToTextBasedProtocolMessage(TextBasedProtocolMessage* message, int fieldOffsetInMessage);
91
92
  uint8_t* m_NewFieldData;
93
  TextBasedProtocolMessage* m_TextBasedProtocolMessage;
94
  int m_NameOffsetInMessage;
95
  size_t m_FieldNameSize;
96
  int m_ValueOffsetInMessage;
97
  size_t m_FieldValueSize;
98
  size_t m_FieldSize;
99
  HeaderField* m_NextField;
100
  bool m_IsEndOfHeaderField;
101
  char m_NameValueSeparator;
102
  bool m_SpacesAllowedBetweenNameAndValue;
103
};
104
105
106
107
108
// -------- Class TextBasedProtocolMessage -----------------
109
110
/**
111
 * @class TextBasedProtocolMessage
112
 * An abstract base class that wraps text-based-protocol header layers (both requests and responses). It is the base class for all those layers.
113
 * This class is not meant to be instantiated, hence the protected c'tor
114
 */
115
class TextBasedProtocolMessage : public Layer
116
{
117
  friend class HeaderField;
118
public:
119
  ~TextBasedProtocolMessage();
120
121
  /**
122
   * Get a pointer to a header field by name. The search is case insensitive, meaning if a field with name "Host" exists and the
123
   * fieldName parameter is "host" (all letter are lower case), this method will return a pointer to "Host" field
124
   * @param[in] fieldName The field name
125
   * @param[in] index Optional parameter. If the field name appears more than once, this parameter will indicate which field to get.
126
   * The default value is 0 (get the first appearance of the field name as appears on the packet)
127
   * @return A pointer to an HeaderField instance, or NULL if field doesn't exist
128
   */
129
  HeaderField* getFieldByName(std::string fieldName, int index = 0) const;
130
131
  /**
132
   * @return A pointer to the first header field exists in this message, or NULL if no such field exists
133
   */
134
0
  HeaderField* getFirstField() const { return m_FieldList; }
135
136
  /**
137
   * Get the field which appears after a certain field
138
   * @param[in] prevField A pointer to the field
139
   * @return The field after prevField or NULL if prevField is the last field. If prevField is NULL, this method will return NULL
140
   */
141
0
  HeaderField* getNextField(HeaderField* prevField) const { if (prevField != NULL) return prevField->getNextField(); else return NULL; }
142
143
  /**
144
   * @return The number of header fields currently in the layer (not including CRLF at the end of the header)
145
   */
146
  int getFieldCount() const;
147
148
  /**
149
   * Add a new header field to this message. This field will be added last (before the end-of-header field)
150
   * @param[in] fieldName The field name
151
   * @param[in] fieldValue The field value
152
   * @return A pointer to the newly created header field, or NULL if the field could not be created
153
   */
154
  virtual HeaderField* addField(const std::string& fieldName, const std::string& fieldValue);
155
156
  /**
157
   * Add a new header field to this message. This field will be added last (before the end-of-header field)
158
   * @param[in] newField The header field to add
159
   * @return A pointer to the newly created header field, or NULL if the field could not be created
160
   */
161
  virtual HeaderField* addField(const HeaderField& newField);
162
163
  /**
164
   * Add the special end-of-header field (see the explanation in HeaderField)
165
   * @return A pointer to the newly created header field, or NULL if the field could not be created
166
   */
167
  HeaderField* addEndOfHeader();
168
169
  /**
170
   * Insert a new field after an existing field
171
   * @param[in] prevField A pointer to the existing field. If it's NULL the new field will be added as first field
172
   * @param[in] fieldName The field name
173
   * @param[in] fieldValue The field value
174
   * @return A pointer to the newly created header field, or NULL if the field could not be created
175
   */
176
  virtual HeaderField* insertField(HeaderField* prevField, const std::string& fieldName, const std::string& fieldValue);
177
178
  /**
179
   * Insert a new field after an existing field
180
   * @param[in] prevFieldName A name of an existing field. If the field doesn't exist NULL will be returned.
181
   * If field name is empty ('') the new field will be added as first field
182
   * @param[in] fieldName The field name
183
   * @param[in] fieldValue The field value
184
   * @return A pointer to the newly created header field, or NULL if the field could not be created
185
   */
186
  virtual HeaderField* insertField(std::string prevFieldName, const std::string& fieldName, const std::string& fieldValue);
187
188
  /**
189
   * Insert a new field after an existing field
190
   * @param[in] prevField A pointer to the existing field
191
   * @param[in] newField The header field to add
192
   * @return A pointer to the newly created header field, or NULL if the field could not be created
193
   */
194
  virtual HeaderField* insertField(HeaderField* prevField, const HeaderField& newField);
195
196
  /**
197
   * Remove a field from the message
198
   * @param[in] fieldToRemove A pointer to the field that should be removed
199
   * @return True if the field was removed successfully, or false otherwise (for example: if fieldToRemove is NULL, if it doesn't exist
200
   * in the message, or if the removal failed)
201
   */
202
  bool removeField(HeaderField* fieldToRemove);
203
204
  /**
205
   * Remove a field from the message
206
   * @param[in] fieldName The name of the field that should be removed
207
   * @param[in] index Optional parameter. If the field name appears more than once, this parameter will indicate which field to remove.
208
   * The default value is 0 (remove the first appearance of the field name as appears on the packet)
209
   * @return True if the field was removed successfully, or false otherwise (for example: if fieldName doesn't exist in the message, or if the removal failed)
210
   */
211
  bool removeField(std::string fieldName, int index = 0);
212
213
  /**
214
   * Indicate whether the header is complete (ending with end-of-header "\r\n\r\n" or "\n\n") or spread over more packets
215
   * @return True if the header is complete or false if not
216
   */
217
  bool isHeaderComplete() const;
218
219
  // implement Layer's abstract methods
220
221
  /**
222
   * Currently set only PayloadLayer for the rest of the data
223
   */
224
  virtual void parseNextLayer();
225
226
  /**
227
   * @return The message length
228
   */
229
  size_t getHeaderLen() const;
230
231
  /**
232
   * Does nothing for this class
233
   */
234
  virtual void computeCalculateFields();
235
236
protected:
237
  TextBasedProtocolMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
238
0
  TextBasedProtocolMessage() : m_FieldList(NULL), m_LastField(NULL), m_FieldsOffset(0) {}
239
240
  // copy c'tor
241
  TextBasedProtocolMessage(const TextBasedProtocolMessage& other);
242
  TextBasedProtocolMessage& operator=(const TextBasedProtocolMessage& other);
243
244
  void copyDataFrom(const TextBasedProtocolMessage& other);
245
246
  void parseFields();
247
  void shiftFieldsOffset(HeaderField* fromField, int numOfBytesToShift);
248
249
  // abstract methods
250
  virtual char getHeaderFieldNameValueSeparator() const = 0;
251
  virtual bool spacesAllowedBetweenHeaderFieldNameAndValue() const = 0;
252
253
  HeaderField* m_FieldList;
254
  HeaderField* m_LastField;
255
  int m_FieldsOffset;
256
  std::multimap<std::string, HeaderField*> m_FieldNameToFieldMap;
257
};
258
259
260
}
261
262
263
#endif // PACKETPP_TEXT_BASED_PROTOCOL_LAYER