/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 |