/src/PcapPlusPlus/Packet++/src/HttpLayer.cpp
Line | Count | Source (jump to first uncovered line) |
1 | 11.7k | #define LOG_MODULE PacketLogModuleHttpLayer |
2 | | |
3 | | #include "Logger.h" |
4 | | #include "GeneralUtils.h" |
5 | | #include "HttpLayer.h" |
6 | | #include <string.h> |
7 | | #include <algorithm> |
8 | | #include <stdlib.h> |
9 | | #include <exception> |
10 | | |
11 | | namespace pcpp |
12 | | { |
13 | | |
14 | | |
15 | | // -------- Class HttpMessage ----------------- |
16 | | |
17 | | |
18 | | HeaderField* HttpMessage::addField(const std::string& fieldName, const std::string& fieldValue) |
19 | 0 | { |
20 | 0 | if (getFieldByName(fieldName) != NULL) |
21 | 0 | { |
22 | 0 | PCPP_LOG_ERROR("Field '" << fieldName << "' already exists!"); |
23 | 0 | return NULL; |
24 | 0 | } |
25 | | |
26 | 0 | return TextBasedProtocolMessage::addField(fieldName, fieldValue); |
27 | 0 | } |
28 | | |
29 | | HeaderField* HttpMessage::addField(const HeaderField& newField) |
30 | 0 | { |
31 | 0 | if (getFieldByName(newField.getFieldName()) != NULL) |
32 | 0 | { |
33 | 0 | PCPP_LOG_ERROR("Field '" << newField.getFieldName() << "' already exists!"); |
34 | 0 | return NULL; |
35 | 0 | } |
36 | | |
37 | 0 | return TextBasedProtocolMessage::addField(newField); |
38 | 0 | } |
39 | | |
40 | | HeaderField* HttpMessage::insertField(HeaderField* prevField, const std::string& fieldName, const std::string& fieldValue) |
41 | 0 | { |
42 | 0 | if (getFieldByName(fieldName) != NULL) |
43 | 0 | { |
44 | 0 | PCPP_LOG_ERROR("Field '" << fieldName << "' already exists!"); |
45 | 0 | return NULL; |
46 | 0 | } |
47 | | |
48 | 0 | return TextBasedProtocolMessage::insertField(prevField, fieldName, fieldValue); |
49 | 0 | } |
50 | | |
51 | | HeaderField* HttpMessage::insertField(HeaderField* prevField, const HeaderField& newField) |
52 | 0 | { |
53 | 0 | if (getFieldByName(newField.getFieldName()) != NULL) |
54 | 0 | { |
55 | 0 | PCPP_LOG_ERROR("Field '" << newField.getFieldName() << "' already exists!"); |
56 | 0 | return NULL; |
57 | 0 | } |
58 | | |
59 | 0 | return TextBasedProtocolMessage::insertField(prevField, newField); |
60 | 0 | } |
61 | | |
62 | | |
63 | | |
64 | | // -------- Class HttpRequestLayer ----------------- |
65 | | |
66 | | HttpRequestLayer::HttpRequestLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : HttpMessage(data, dataLen, prevLayer, packet) |
67 | 7.55k | { |
68 | 7.55k | m_Protocol = HTTPRequest; |
69 | 7.55k | m_FirstLine = new HttpRequestFirstLine(this); |
70 | 7.55k | m_FieldsOffset = m_FirstLine->getSize(); |
71 | 7.55k | parseFields(); |
72 | 7.55k | } |
73 | | |
74 | | HttpRequestLayer::HttpRequestLayer(HttpMethod method, std::string uri, HttpVersion version) |
75 | 0 | { |
76 | 0 | m_Protocol = HTTPRequest; |
77 | 0 | m_FirstLine = new HttpRequestFirstLine(this, method, version, uri); |
78 | 0 | m_FieldsOffset = m_FirstLine->getSize(); |
79 | 0 | } |
80 | | |
81 | | HttpRequestLayer::HttpRequestLayer(const HttpRequestLayer& other) : HttpMessage(other) |
82 | 0 | { |
83 | 0 | m_FirstLine = new HttpRequestFirstLine(this); |
84 | 0 | } |
85 | | |
86 | | HttpRequestLayer& HttpRequestLayer::operator=(const HttpRequestLayer& other) |
87 | 0 | { |
88 | 0 | HttpMessage::operator=(other); |
89 | |
|
90 | 0 | if (m_FirstLine != NULL) |
91 | 0 | delete m_FirstLine; |
92 | |
|
93 | 0 | m_FirstLine = new HttpRequestFirstLine(this); |
94 | |
|
95 | 0 | return *this; |
96 | 0 | } |
97 | | |
98 | | |
99 | | std::string HttpRequestLayer::getUrl() const |
100 | 0 | { |
101 | 0 | HeaderField* hostField = getFieldByName(PCPP_HTTP_HOST_FIELD); |
102 | 0 | if (hostField == NULL) |
103 | 0 | return m_FirstLine->getUri(); |
104 | | |
105 | 0 | return hostField->getFieldValue() + m_FirstLine->getUri(); |
106 | 0 | } |
107 | | |
108 | | HttpRequestLayer::~HttpRequestLayer() |
109 | 7.55k | { |
110 | 7.55k | delete m_FirstLine; |
111 | 7.55k | } |
112 | | |
113 | | std::string HttpRequestLayer::toString() const |
114 | 0 | { |
115 | 0 | static const int maxLengthToPrint = 120; |
116 | 0 | std::string result = "HTTP request, "; |
117 | 0 | int size = m_FirstLine->getSize() - 2; // the -2 is to remove \r\n at the end of the first line |
118 | 0 | if (size <= 0) |
119 | 0 | { |
120 | 0 | result += std::string("CORRUPT DATA"); |
121 | 0 | return result; |
122 | 0 | } |
123 | 0 | if (size <= maxLengthToPrint) |
124 | 0 | { |
125 | 0 | char* firstLine = new char[size+1]; |
126 | 0 | strncpy(firstLine, (char*)m_Data, size); |
127 | 0 | firstLine[size] = 0; |
128 | 0 | result += std::string(firstLine); |
129 | 0 | delete[] firstLine; |
130 | 0 | } |
131 | 0 | else |
132 | 0 | { |
133 | 0 | char firstLine[maxLengthToPrint+1]; |
134 | 0 | strncpy(firstLine, (char*)m_Data, maxLengthToPrint-3); |
135 | 0 | firstLine[maxLengthToPrint-3] = '.'; |
136 | 0 | firstLine[maxLengthToPrint-2] = '.'; |
137 | 0 | firstLine[maxLengthToPrint-1] = '.'; |
138 | 0 | firstLine[maxLengthToPrint] = 0; |
139 | 0 | result += std::string(firstLine); |
140 | 0 | } |
141 | |
|
142 | 0 | return result; |
143 | 0 | } |
144 | | |
145 | | |
146 | | |
147 | | |
148 | | |
149 | | |
150 | | |
151 | | // -------- Class HttpRequestFirstLine ----------------- |
152 | | |
153 | | |
154 | | const std::string MethodEnumToString[9] = { |
155 | | "GET", |
156 | | "HEAD", |
157 | | "POST", |
158 | | "PUT", |
159 | | "DELETE", |
160 | | "TRACE", |
161 | | "OPTIONS", |
162 | | "CONNECT", |
163 | | "PATCH" |
164 | | }; |
165 | | |
166 | | const std::string VersionEnumToString[3] = { |
167 | | "0.9", |
168 | | "1.0", |
169 | | "1.1" |
170 | | }; |
171 | | |
172 | | HttpRequestFirstLine::HttpRequestFirstLine(HttpRequestLayer* httpRequest) : m_HttpRequest(httpRequest) |
173 | 7.55k | { |
174 | 7.55k | m_Method = parseMethod((char*)m_HttpRequest->m_Data, m_HttpRequest->getDataLen()); |
175 | 7.55k | if (m_Method == HttpRequestLayer::HttpMethodUnknown) |
176 | 0 | { |
177 | 0 | m_UriOffset = -1; |
178 | 0 | PCPP_LOG_DEBUG("Couldn't resolve HTTP request method"); |
179 | 0 | m_IsComplete = false; |
180 | 0 | m_Version = HttpVersionUnknown; |
181 | 0 | m_VersionOffset = -1; |
182 | 0 | m_FirstLineEndOffset = m_HttpRequest->getDataLen(); |
183 | 0 | return; |
184 | 0 | } |
185 | 7.55k | else |
186 | 7.55k | m_UriOffset = MethodEnumToString[m_Method].length() + 1; |
187 | | |
188 | 7.55k | parseVersion(); |
189 | 7.55k | if(m_VersionOffset < 0) |
190 | 2.49k | { |
191 | 2.49k | m_IsComplete = false; |
192 | 2.49k | m_FirstLineEndOffset = m_HttpRequest->getDataLen(); |
193 | 2.49k | return; |
194 | 2.49k | } |
195 | | |
196 | 5.05k | char* endOfFirstLine; |
197 | 5.05k | if ((endOfFirstLine = (char*)memchr((char*)(m_HttpRequest->m_Data + m_VersionOffset), '\n', m_HttpRequest->m_DataLen-(size_t)m_VersionOffset)) != NULL) |
198 | 208 | { |
199 | 208 | m_FirstLineEndOffset = endOfFirstLine - (char*)m_HttpRequest->m_Data + 1; |
200 | 208 | m_IsComplete = true; |
201 | 208 | } |
202 | 4.85k | else |
203 | 4.85k | { |
204 | 4.85k | m_FirstLineEndOffset = m_HttpRequest->getDataLen(); |
205 | 4.85k | m_IsComplete = false; |
206 | 4.85k | } |
207 | | |
208 | 5.05k | if (Logger::getInstance().isDebugEnabled(PacketLogModuleHttpLayer)) |
209 | 0 | { |
210 | 0 | std::string method = m_Method == HttpRequestLayer::HttpMethodUnknown? "Unknown" : MethodEnumToString[m_Method]; |
211 | 0 | PCPP_LOG_DEBUG( |
212 | 0 | "Method='" << method << "'; " |
213 | 0 | << "HTTP version='" << VersionEnumToString[m_Version] << "'; " |
214 | 0 | << "URI='" << getUri() << "'"); |
215 | 0 | } |
216 | 5.05k | } |
217 | | |
218 | | HttpRequestFirstLine::HttpRequestFirstLine(HttpRequestLayer* httpRequest, HttpRequestLayer::HttpMethod method, HttpVersion version, std::string uri) |
219 | 0 | try // throw(HttpRequestFirstLineException) |
220 | 0 | { |
221 | 0 | if (method == HttpRequestLayer::HttpMethodUnknown) |
222 | 0 | { |
223 | 0 | m_Exception.setMessage("Method supplied was HttpMethodUnknown"); |
224 | 0 | throw m_Exception; |
225 | 0 | } |
226 | | |
227 | 0 | if (version == HttpVersionUnknown) |
228 | 0 | { |
229 | 0 | m_Exception.setMessage("Version supplied was HttpVersionUnknown"); |
230 | 0 | throw m_Exception; |
231 | 0 | } |
232 | | |
233 | 0 | m_HttpRequest = httpRequest; |
234 | |
|
235 | 0 | m_Method = method; |
236 | 0 | m_Version = version; |
237 | |
|
238 | 0 | std::string firstLine = MethodEnumToString[m_Method] + " " + uri + " " + "HTTP/" + VersionEnumToString[m_Version] + "\r\n"; |
239 | |
|
240 | 0 | m_UriOffset = MethodEnumToString[m_Method].length() + 1; |
241 | 0 | m_FirstLineEndOffset = firstLine.length(); |
242 | 0 | m_VersionOffset = m_UriOffset + uri.length() + 6; |
243 | |
|
244 | 0 | m_HttpRequest->m_DataLen = firstLine.length(); |
245 | 0 | m_HttpRequest->m_Data = new uint8_t[m_HttpRequest->m_DataLen]; |
246 | 0 | memcpy(m_HttpRequest->m_Data, firstLine.c_str(), m_HttpRequest->m_DataLen); |
247 | |
|
248 | 0 | m_IsComplete = true; |
249 | 0 | } |
250 | 0 | catch(const HttpRequestFirstLineException&) |
251 | 0 | { |
252 | 0 | throw; |
253 | 0 | } |
254 | 0 | catch(...) |
255 | 0 | { |
256 | 0 | std::terminate(); |
257 | 0 | } |
258 | | |
259 | | HttpRequestLayer::HttpMethod HttpRequestFirstLine::parseMethod(char* data, size_t dataLen) |
260 | 34.1k | { |
261 | 34.1k | if (dataLen < 4) |
262 | 205 | { |
263 | 205 | return HttpRequestLayer::HttpMethodUnknown; |
264 | 205 | } |
265 | | |
266 | 33.8k | switch (data[0]) |
267 | 33.8k | { |
268 | 188 | case 'G': |
269 | 188 | if (data[1] == 'E' && data[2] == 'T' && data[3] == ' ') |
270 | 30 | return HttpRequestLayer::HttpGET; |
271 | 158 | else |
272 | 158 | return HttpRequestLayer::HttpMethodUnknown; |
273 | 0 | break; |
274 | | |
275 | 1.80k | case 'D': |
276 | 1.80k | if (dataLen < 7) |
277 | 198 | return HttpRequestLayer::HttpMethodUnknown; |
278 | 1.60k | else if (data[1] == 'E' && data[2] == 'L' && data[3] == 'E' && data[4] == 'T' && data[5] == 'E' && data[6] == ' ') |
279 | 62 | return HttpRequestLayer::HttpDELETE; |
280 | 1.54k | else |
281 | 1.54k | return HttpRequestLayer::HttpMethodUnknown; |
282 | 0 | break; |
283 | | |
284 | 1.21k | case 'C': |
285 | 1.21k | if (dataLen < 8) |
286 | 250 | return HttpRequestLayer::HttpMethodUnknown; |
287 | 960 | else if (data[1] == 'O' && data[2] == 'N' && data[3] == 'N' && data[4] == 'E' && data[5] == 'C' && data[6] == 'T' && data[7] == ' ') |
288 | 2 | return HttpRequestLayer::HttpCONNECT; |
289 | 958 | else |
290 | 958 | return HttpRequestLayer::HttpMethodUnknown; |
291 | 0 | break; |
292 | | |
293 | 3.40k | case 'T': |
294 | 3.40k | if (dataLen < 6) |
295 | 204 | return HttpRequestLayer::HttpMethodUnknown; |
296 | 3.20k | else if (data[1] == 'R' && data[2] == 'A' && data[3] == 'C' && data[4] == 'E' && data[5] == ' ') |
297 | 426 | return HttpRequestLayer::HttpTRACE; |
298 | 2.77k | else |
299 | 2.77k | return HttpRequestLayer::HttpMethodUnknown; |
300 | 0 | break; |
301 | | |
302 | | |
303 | 5.60k | case 'H': |
304 | 5.60k | if (dataLen < 5) |
305 | 214 | return HttpRequestLayer::HttpMethodUnknown; |
306 | 5.38k | else if (data[1] == 'E' && data[2] == 'A' && data[3] == 'D' && data[4] == ' ') |
307 | 1.19k | return HttpRequestLayer::HttpHEAD; |
308 | 4.19k | else |
309 | 4.19k | return HttpRequestLayer::HttpMethodUnknown; |
310 | 0 | break; |
311 | | |
312 | 2.55k | case 'O': |
313 | 2.55k | if (dataLen < 8) |
314 | 238 | return HttpRequestLayer::HttpMethodUnknown; |
315 | 2.31k | else if (data[1] == 'P' && data[2] == 'T' && data[3] == 'I' && data[4] == 'O' && data[5] == 'N' && data[6] == 'S' && data[7] == ' ') |
316 | 190 | return HttpRequestLayer::HttpOPTIONS; |
317 | 2.12k | else |
318 | 2.12k | return HttpRequestLayer::HttpMethodUnknown; |
319 | 0 | break; |
320 | | |
321 | 17.4k | case 'P': |
322 | 17.4k | switch (data[1]) |
323 | 17.4k | { |
324 | 13.4k | case 'U': |
325 | 13.4k | if (data[2] == 'T' && data[3] == ' ') |
326 | 12.6k | return HttpRequestLayer::HttpPUT; |
327 | 833 | else |
328 | 833 | return HttpRequestLayer::HttpMethodUnknown; |
329 | 0 | break; |
330 | | |
331 | 729 | case 'O': |
332 | 729 | if (dataLen < 5) |
333 | 206 | return HttpRequestLayer::HttpMethodUnknown; |
334 | 523 | else if (data[2] == 'S' && data[3] == 'T' && data[4] == ' ') |
335 | 14 | return HttpRequestLayer::HttpPOST; |
336 | 509 | else |
337 | 509 | return HttpRequestLayer::HttpMethodUnknown; |
338 | 0 | break; |
339 | | |
340 | 2.92k | case 'A': |
341 | 2.92k | if (dataLen < 6) |
342 | 194 | return HttpRequestLayer::HttpMethodUnknown; |
343 | 2.73k | else if (data[2] == 'T' && data[3] == 'C' && data[4] == 'H' && data[5] == ' ') |
344 | 554 | return HttpRequestLayer::HttpPATCH; |
345 | 2.17k | else |
346 | 2.17k | return HttpRequestLayer::HttpMethodUnknown; |
347 | 0 | break; |
348 | | |
349 | 348 | default: |
350 | 348 | return HttpRequestLayer::HttpMethodUnknown; |
351 | 17.4k | } |
352 | 0 | break; |
353 | | |
354 | 1.66k | default: |
355 | 1.66k | return HttpRequestLayer::HttpMethodUnknown; |
356 | 33.8k | } |
357 | 33.8k | } |
358 | | |
359 | | void HttpRequestFirstLine::parseVersion() |
360 | 7.55k | { |
361 | 7.55k | char* data = (char*)(m_HttpRequest->m_Data + m_UriOffset); |
362 | 7.55k | char* verPos = cross_platform_memmem(data, m_HttpRequest->getDataLen() - m_UriOffset, " HTTP/", 6); |
363 | 7.55k | if (verPos == NULL) |
364 | 2.11k | { |
365 | 2.11k | m_Version = HttpVersionUnknown; |
366 | 2.11k | m_VersionOffset = -1; |
367 | 2.11k | return; |
368 | 2.11k | } |
369 | | |
370 | | // verify packet doesn't end before the version, meaning still left place for " HTTP/x.y" (9 chars) |
371 | 5.44k | if ((verPos + 9 - (char*)m_HttpRequest->m_Data) > m_HttpRequest->getDataLen()) |
372 | 383 | { |
373 | 383 | m_Version = HttpVersionUnknown; |
374 | 383 | m_VersionOffset = -1; |
375 | 383 | return; |
376 | 383 | } |
377 | | |
378 | | //skip " HTTP/" (6 chars) |
379 | 5.05k | verPos += 6; |
380 | 5.05k | switch (verPos[0]) |
381 | 5.05k | { |
382 | 1.22k | case '0': |
383 | 1.22k | if (verPos[1] == '.' && verPos[2] == '9') |
384 | 11 | m_Version = ZeroDotNine; |
385 | 1.21k | else |
386 | 1.21k | m_Version = HttpVersionUnknown; |
387 | 1.22k | break; |
388 | | |
389 | 2.77k | case '1': |
390 | 2.77k | if (verPos[1] == '.' && verPos[2] == '0') |
391 | 67 | m_Version = OneDotZero; |
392 | 2.71k | else if (verPos[1] == '.' && verPos[2] == '1') |
393 | 1.55k | m_Version = OneDotOne; |
394 | 1.15k | else |
395 | 1.15k | m_Version = HttpVersionUnknown; |
396 | 2.77k | break; |
397 | | |
398 | 1.06k | default: |
399 | 1.06k | m_Version = HttpVersionUnknown; |
400 | 5.05k | } |
401 | | |
402 | 5.05k | m_VersionOffset = verPos - (char*)m_HttpRequest->m_Data; |
403 | 5.05k | } |
404 | | |
405 | | bool HttpRequestFirstLine::setMethod(HttpRequestLayer::HttpMethod newMethod) |
406 | 0 | { |
407 | 0 | if (newMethod == HttpRequestLayer::HttpMethodUnknown) |
408 | 0 | { |
409 | 0 | PCPP_LOG_ERROR("Requested method is HttpMethodUnknown"); |
410 | 0 | return false; |
411 | 0 | } |
412 | | |
413 | | //extend or shorten layer |
414 | 0 | int lengthDifference = MethodEnumToString[newMethod].length() - MethodEnumToString[m_Method].length(); |
415 | 0 | if (lengthDifference > 0) |
416 | 0 | { |
417 | 0 | if (!m_HttpRequest->extendLayer(0, lengthDifference)) |
418 | 0 | { |
419 | 0 | PCPP_LOG_ERROR("Cannot change layer size"); |
420 | 0 | return false; |
421 | 0 | } |
422 | 0 | } |
423 | 0 | else if (lengthDifference < 0) |
424 | 0 | { |
425 | 0 | if (!m_HttpRequest->shortenLayer(0, 0-lengthDifference)) |
426 | 0 | { |
427 | 0 | PCPP_LOG_ERROR("Cannot change layer size"); |
428 | 0 | return false; |
429 | |
|
430 | 0 | } |
431 | 0 | } |
432 | | |
433 | 0 | if (lengthDifference != 0) |
434 | 0 | m_HttpRequest->shiftFieldsOffset(m_HttpRequest->getFirstField(), lengthDifference); |
435 | |
|
436 | 0 | memcpy(m_HttpRequest->m_Data, MethodEnumToString[newMethod].c_str(), MethodEnumToString[newMethod].length()); |
437 | |
|
438 | 0 | m_Method = newMethod; |
439 | 0 | m_UriOffset += lengthDifference; |
440 | 0 | m_VersionOffset += lengthDifference; |
441 | |
|
442 | 0 | return true; |
443 | 0 | } |
444 | | |
445 | | std::string HttpRequestFirstLine::getUri() const |
446 | 0 | { |
447 | 0 | std::string result; |
448 | 0 | if (m_UriOffset != -1 && m_VersionOffset != -1) |
449 | 0 | result.assign((const char*)m_HttpRequest->m_Data + m_UriOffset, m_VersionOffset - 6 - m_UriOffset); |
450 | | |
451 | | //else first line is illegal, return empty string |
452 | |
|
453 | 0 | return result; |
454 | 0 | } |
455 | | |
456 | | bool HttpRequestFirstLine::setUri(std::string newUri) |
457 | 0 | { |
458 | | // make sure the new URI begins with "/" |
459 | 0 | if (newUri.compare(0, 1, "/") != 0) |
460 | 0 | newUri = "/" + newUri; |
461 | | |
462 | | //extend or shorten layer |
463 | 0 | std::string currentUri = getUri(); |
464 | 0 | int lengthDifference = newUri.length() - currentUri.length(); |
465 | 0 | if (lengthDifference > 0) |
466 | 0 | { |
467 | 0 | if (!m_HttpRequest->extendLayer(m_UriOffset, lengthDifference)) |
468 | 0 | { |
469 | 0 | PCPP_LOG_ERROR("Cannot change layer size"); |
470 | 0 | return false; |
471 | 0 | } |
472 | 0 | } |
473 | 0 | else if (lengthDifference < 0) |
474 | 0 | { |
475 | 0 | if (!m_HttpRequest->shortenLayer(m_UriOffset, 0-lengthDifference)) |
476 | 0 | { |
477 | 0 | PCPP_LOG_ERROR("Cannot change layer size"); |
478 | 0 | return false; |
479 | 0 | } |
480 | 0 | } |
481 | | |
482 | 0 | if (lengthDifference != 0) |
483 | 0 | m_HttpRequest->shiftFieldsOffset(m_HttpRequest->getFirstField(), lengthDifference); |
484 | |
|
485 | 0 | memcpy(m_HttpRequest->m_Data + m_UriOffset, newUri.c_str(), newUri.length()); |
486 | |
|
487 | 0 | m_VersionOffset += lengthDifference; |
488 | |
|
489 | 0 | return true; |
490 | 0 | } |
491 | | |
492 | | void HttpRequestFirstLine::setVersion(HttpVersion newVersion) |
493 | 0 | { |
494 | 0 | if (m_VersionOffset == -1) |
495 | 0 | return; |
496 | | |
497 | 0 | if (newVersion == HttpVersionUnknown) |
498 | 0 | return; |
499 | | |
500 | 0 | char* verPos = (char*)(m_HttpRequest->m_Data + m_VersionOffset); |
501 | 0 | memcpy(verPos, VersionEnumToString[newVersion].c_str(), 3); |
502 | |
|
503 | 0 | m_Version = newVersion; |
504 | 0 | } |
505 | | |
506 | | |
507 | | |
508 | | |
509 | | |
510 | | |
511 | | // -------- Class HttpResponseLayer ----------------- |
512 | | |
513 | | |
514 | | |
515 | | const std::string StatusCodeEnumToString[80] = { |
516 | | "Continue", |
517 | | "Switching Protocols", |
518 | | "Processing", |
519 | | "OK", |
520 | | "Created", |
521 | | "Accepted", |
522 | | "Non-Authoritative Information", |
523 | | "No Content", |
524 | | "Reset Content", |
525 | | "Partial Content", |
526 | | "Multi-Status", |
527 | | "Already Reported", |
528 | | "IM Used", |
529 | | "Multiple Choices", |
530 | | "Moved Permanently", |
531 | | "Found", |
532 | | "See Other", |
533 | | "Not Modified", |
534 | | "Use Proxy", |
535 | | "Switch Proxy", |
536 | | "Temporary Redirect", |
537 | | "Permanent Redirect", |
538 | | "Bad Request", |
539 | | "Unauthorized", |
540 | | "Payment Required", |
541 | | "Forbidden", |
542 | | "Not Found", |
543 | | "Method Not Allowed", |
544 | | "Not Acceptable", |
545 | | "Proxy Authentication Required", |
546 | | "Request Timeout", |
547 | | "Conflict", |
548 | | "Gone", |
549 | | "Length Required", |
550 | | "Precondition Failed", |
551 | | "Request Entity Too Large", |
552 | | "Request-URI Too Long", |
553 | | "Unsupported Media Type", |
554 | | "Requested Range Not Satisfiable", |
555 | | "Expectation Failed", |
556 | | "I'm a teapot", |
557 | | "Authentication Timeout", |
558 | | "Method Failure", |
559 | | "Unprocessable Entity", |
560 | | "Locked", |
561 | | "Failed Dependency", |
562 | | "Upgrade Required", |
563 | | "Precondition Required", |
564 | | "Too Many Requests", |
565 | | "Request Header Fields Too Large", |
566 | | "Login Timeout", |
567 | | "No Response", |
568 | | "Retry With", |
569 | | "Blocked by Windows Parental Controls", |
570 | | "Unavailable For Legal Reasons", |
571 | | "Request Header Too Large", |
572 | | "Cert Error", |
573 | | "No Cert", |
574 | | "HTTP to HTTPS", |
575 | | "Token expired/invalid", |
576 | | "Client Closed Request", |
577 | | "Internal Server Error", |
578 | | "Not Implemented", |
579 | | "Bad Gateway", |
580 | | "Service Unavailable", |
581 | | "Gateway Timeout", |
582 | | "HTTP Version Not Supported", |
583 | | "Variant Also Negotiates", |
584 | | "Insufficient Storage", |
585 | | "Loop Detected", |
586 | | "Bandwidth Limit Exceeded", |
587 | | "Not Extended", |
588 | | "Network Authentication Required", |
589 | | "Origin Error", |
590 | | "Web server is down", |
591 | | "Connection timed out", |
592 | | "Proxy Declined Request", |
593 | | "A timeout occurred", |
594 | | "Network read timeout error", |
595 | | "Network connect timeout error" |
596 | | }; |
597 | | |
598 | | |
599 | | const int StatusCodeEnumToInt[80] = { |
600 | | 100, |
601 | | 101, |
602 | | 102, |
603 | | 200, |
604 | | 201, |
605 | | 202, |
606 | | 203, |
607 | | 204, |
608 | | 205, |
609 | | 206, |
610 | | 207, |
611 | | 208, |
612 | | 226, |
613 | | 300, |
614 | | 301, |
615 | | 302, |
616 | | 303, |
617 | | 304, |
618 | | 305, |
619 | | 306, |
620 | | 307, |
621 | | 308, |
622 | | 400, |
623 | | 401, |
624 | | 402, |
625 | | 403, |
626 | | 404, |
627 | | 405, |
628 | | 406, |
629 | | 407, |
630 | | 408, |
631 | | 409, |
632 | | 410, |
633 | | 411, |
634 | | 412, |
635 | | 413, |
636 | | 414, |
637 | | 415, |
638 | | 416, |
639 | | 417, |
640 | | 418, |
641 | | 419, |
642 | | 420, |
643 | | 422, |
644 | | 423, |
645 | | 424, |
646 | | 426, |
647 | | 428, |
648 | | 429, |
649 | | 431, |
650 | | 440, |
651 | | 444, |
652 | | 449, |
653 | | 450, |
654 | | 451, |
655 | | 494, |
656 | | 495, |
657 | | 496, |
658 | | 497, |
659 | | 498, |
660 | | 499, |
661 | | 500, |
662 | | 501, |
663 | | 502, |
664 | | 503, |
665 | | 504, |
666 | | 505, |
667 | | 506, |
668 | | 507, |
669 | | 508, |
670 | | 509, |
671 | | 510, |
672 | | 511, |
673 | | 520, |
674 | | 521, |
675 | | 522, |
676 | | 523, |
677 | | 524, |
678 | | 598, |
679 | | 599 |
680 | | }; |
681 | | |
682 | | |
683 | | |
684 | | HttpResponseLayer::HttpResponseLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : HttpMessage(data, dataLen, prevLayer, packet) |
685 | 13.3k | { |
686 | 13.3k | m_Protocol = HTTPResponse; |
687 | 13.3k | m_FirstLine = new HttpResponseFirstLine(this); |
688 | 13.3k | m_FieldsOffset = m_FirstLine->getSize(); |
689 | 13.3k | parseFields(); |
690 | 13.3k | } |
691 | | |
692 | | HttpResponseLayer::HttpResponseLayer(HttpVersion version, HttpResponseLayer::HttpResponseStatusCode statusCode, std::string statusCodeString) |
693 | 0 | { |
694 | 0 | m_Protocol = HTTPResponse; |
695 | 0 | m_FirstLine = new HttpResponseFirstLine(this, version, statusCode, statusCodeString); |
696 | 0 | m_FieldsOffset = m_FirstLine->getSize(); |
697 | 0 | } |
698 | | |
699 | | HttpResponseLayer::~HttpResponseLayer() |
700 | 13.3k | { |
701 | 13.3k | delete m_FirstLine; |
702 | 13.3k | } |
703 | | |
704 | | |
705 | | HttpResponseLayer::HttpResponseLayer(const HttpResponseLayer& other) : HttpMessage(other) |
706 | 0 | { |
707 | 0 | m_FirstLine = new HttpResponseFirstLine(this); |
708 | 0 | } |
709 | | |
710 | | HttpResponseLayer& HttpResponseLayer::operator=(const HttpResponseLayer& other) |
711 | 0 | { |
712 | 0 | HttpMessage::operator=(other); |
713 | |
|
714 | 0 | if (m_FirstLine != NULL) |
715 | 0 | delete m_FirstLine; |
716 | |
|
717 | 0 | m_FirstLine = new HttpResponseFirstLine(this); |
718 | |
|
719 | 0 | return *this; |
720 | 0 | } |
721 | | |
722 | | |
723 | | HeaderField* HttpResponseLayer::setContentLength(int contentLength, const std::string &prevFieldName) |
724 | 0 | { |
725 | 0 | std::ostringstream contentLengthAsString; |
726 | 0 | contentLengthAsString << contentLength; |
727 | 0 | std::string contentLengthFieldName(PCPP_HTTP_CONTENT_LENGTH_FIELD); |
728 | 0 | HeaderField* contentLengthField = getFieldByName(contentLengthFieldName); |
729 | 0 | if (contentLengthField == NULL) |
730 | 0 | { |
731 | 0 | HeaderField* prevField = getFieldByName(prevFieldName); |
732 | 0 | contentLengthField = insertField(prevField, PCPP_HTTP_CONTENT_LENGTH_FIELD, contentLengthAsString.str()); |
733 | 0 | } |
734 | 0 | else |
735 | 0 | contentLengthField->setFieldValue(contentLengthAsString.str()); |
736 | |
|
737 | 0 | return contentLengthField; |
738 | 0 | } |
739 | | |
740 | | int HttpResponseLayer::getContentLength() const |
741 | 0 | { |
742 | 0 | std::string contentLengthFieldName(PCPP_HTTP_CONTENT_LENGTH_FIELD); |
743 | 0 | std::transform(contentLengthFieldName.begin(), contentLengthFieldName.end(), contentLengthFieldName.begin(), ::tolower); |
744 | 0 | HeaderField* contentLengthField = getFieldByName(contentLengthFieldName); |
745 | 0 | if (contentLengthField != NULL) |
746 | 0 | return atoi(contentLengthField->getFieldValue().c_str()); |
747 | 0 | return 0; |
748 | 0 | } |
749 | | |
750 | | std::string HttpResponseLayer::toString() const |
751 | 0 | { |
752 | 0 | static const int maxLengthToPrint = 120; |
753 | 0 | std::string result = "HTTP response, "; |
754 | 0 | int size = m_FirstLine->getSize() - 2; // the -2 is to remove \r\n at the end of the first line |
755 | 0 | if (size <= maxLengthToPrint) |
756 | 0 | { |
757 | 0 | char* firstLine = new char[size+1]; |
758 | 0 | strncpy(firstLine, (char*)m_Data, size); |
759 | 0 | firstLine[size] = 0; |
760 | 0 | result += std::string(firstLine); |
761 | 0 | delete[] firstLine; |
762 | 0 | } |
763 | 0 | else |
764 | 0 | { |
765 | 0 | char firstLine[maxLengthToPrint+1]; |
766 | 0 | strncpy(firstLine, (char*)m_Data, maxLengthToPrint-3); |
767 | 0 | firstLine[maxLengthToPrint-3] = '.'; |
768 | 0 | firstLine[maxLengthToPrint-2] = '.'; |
769 | 0 | firstLine[maxLengthToPrint-1] = '.'; |
770 | 0 | firstLine[maxLengthToPrint] = 0; |
771 | 0 | result += std::string(firstLine); |
772 | 0 | } |
773 | |
|
774 | 0 | return result; |
775 | 0 | } |
776 | | |
777 | | |
778 | | |
779 | | |
780 | | |
781 | | |
782 | | |
783 | | |
784 | | // -------- Class HttpResponseFirstLine ----------------- |
785 | | |
786 | | |
787 | | |
788 | | int HttpResponseFirstLine::getStatusCodeAsInt() const |
789 | 0 | { |
790 | 0 | return StatusCodeEnumToInt[m_StatusCode]; |
791 | 0 | } |
792 | | |
793 | | std::string HttpResponseFirstLine::getStatusCodeString() const |
794 | 0 | { |
795 | 0 | std::string result; |
796 | 0 | const int statusStringOffset = 13; |
797 | 0 | if (m_StatusCode != HttpResponseLayer::HttpStatusCodeUnknown) |
798 | 0 | { |
799 | 0 | int statusStringEndOffset = m_FirstLineEndOffset - 2; |
800 | 0 | if ((*(m_HttpResponse->m_Data + statusStringEndOffset)) != '\r') |
801 | 0 | statusStringEndOffset++; |
802 | 0 | result.assign((char*)(m_HttpResponse->m_Data + statusStringOffset), statusStringEndOffset-statusStringOffset); |
803 | 0 | } |
804 | | |
805 | | //else first line is illegal, return empty string |
806 | |
|
807 | 0 | return result; |
808 | 0 | } |
809 | | |
810 | | bool HttpResponseFirstLine::setStatusCode(HttpResponseLayer::HttpResponseStatusCode newStatusCode, std::string statusCodeString) |
811 | 0 | { |
812 | 0 | if (newStatusCode == HttpResponseLayer::HttpStatusCodeUnknown) |
813 | 0 | { |
814 | 0 | PCPP_LOG_ERROR("Requested status code is HttpStatusCodeUnknown"); |
815 | 0 | return false; |
816 | 0 | } |
817 | | |
818 | | //extend or shorten layer |
819 | | |
820 | 0 | size_t statusStringOffset = 13; |
821 | 0 | if (statusCodeString == "") |
822 | 0 | statusCodeString = StatusCodeEnumToString[newStatusCode]; |
823 | 0 | int lengthDifference = statusCodeString.length() - getStatusCodeString().length(); |
824 | 0 | if (lengthDifference > 0) |
825 | 0 | { |
826 | 0 | if (!m_HttpResponse->extendLayer(statusStringOffset, lengthDifference)) |
827 | 0 | { |
828 | 0 | PCPP_LOG_ERROR("Cannot change layer size"); |
829 | 0 | return false; |
830 | 0 | } |
831 | 0 | } |
832 | 0 | else if (lengthDifference < 0) |
833 | 0 | { |
834 | 0 | if (!m_HttpResponse->shortenLayer(statusStringOffset, 0-lengthDifference)) |
835 | 0 | { |
836 | 0 | PCPP_LOG_ERROR("Cannot change layer size"); |
837 | 0 | return false; |
838 | |
|
839 | 0 | } |
840 | 0 | } |
841 | | |
842 | 0 | if (lengthDifference != 0) |
843 | 0 | m_HttpResponse->shiftFieldsOffset(m_HttpResponse->getFirstField(), lengthDifference); |
844 | | |
845 | | // copy status string |
846 | 0 | memcpy(m_HttpResponse->m_Data+statusStringOffset, statusCodeString.c_str(), statusCodeString.length()); |
847 | | |
848 | | // change status code |
849 | 0 | std::ostringstream statusCodeAsString; |
850 | 0 | statusCodeAsString << StatusCodeEnumToInt[newStatusCode]; |
851 | 0 | memcpy(m_HttpResponse->m_Data+9, statusCodeAsString.str().c_str(), 3); |
852 | |
|
853 | 0 | m_StatusCode = newStatusCode; |
854 | |
|
855 | 0 | m_FirstLineEndOffset += lengthDifference; |
856 | |
|
857 | 0 | return true; |
858 | |
|
859 | 0 | } |
860 | | |
861 | | void HttpResponseFirstLine::setVersion(HttpVersion newVersion) |
862 | 0 | { |
863 | 0 | if (newVersion == HttpVersionUnknown) |
864 | 0 | return; |
865 | | |
866 | 0 | char* verPos = (char*)(m_HttpResponse->m_Data + 5); |
867 | 0 | memcpy(verPos, VersionEnumToString[newVersion].c_str(), 3); |
868 | |
|
869 | 0 | m_Version = newVersion; |
870 | 0 | } |
871 | | |
872 | | HttpResponseLayer::HttpResponseStatusCode HttpResponseFirstLine::validateStatusCode(char* data, size_t dataLen, HttpResponseLayer::HttpResponseStatusCode potentialCode) |
873 | 67.3k | { |
874 | 67.3k | if (dataLen < 1 || data[0] != ' ') |
875 | 40.6k | return HttpResponseLayer::HttpStatusCodeUnknown; |
876 | | |
877 | 26.7k | return potentialCode; |
878 | 67.3k | } |
879 | | |
880 | | HttpResponseLayer::HttpResponseStatusCode HttpResponseFirstLine::parseStatusCode(char* data, size_t dataLen) |
881 | 97.9k | { |
882 | 97.9k | if (parseVersion(data, dataLen) == HttpVersionUnknown) |
883 | 17.8k | return HttpResponseLayer::HttpStatusCodeUnknown; |
884 | | |
885 | | // minimum data should be 12B long: "HTTP/x.y XXX" |
886 | 80.0k | if (dataLen < 12) |
887 | 219 | return HttpResponseLayer::HttpStatusCodeUnknown; |
888 | | |
889 | 79.8k | char* statusCodeData = data + 9; |
890 | 79.8k | size_t statusCodeDataLen = dataLen - 9; |
891 | | |
892 | 79.8k | switch (statusCodeData[0]) |
893 | 79.8k | { |
894 | 3.30k | case '1': |
895 | 3.30k | switch (statusCodeData[1]) |
896 | 3.30k | { |
897 | 1.83k | case '0': |
898 | 1.83k | switch (statusCodeData[2]) |
899 | 1.83k | { |
900 | 241 | case '0': |
901 | 241 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http100Continue); |
902 | 862 | case '1': |
903 | 862 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http101SwitchingProtocols); |
904 | 660 | case '2': |
905 | 660 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http102Processing); |
906 | 74 | default: |
907 | 74 | return HttpResponseLayer::HttpStatusCodeUnknown; |
908 | 1.83k | }; |
909 | |
|
910 | 0 | break; |
911 | | |
912 | 1.46k | default: |
913 | 1.46k | return HttpResponseLayer::HttpStatusCodeUnknown; |
914 | 3.30k | }; |
915 | |
|
916 | 0 | break; |
917 | 6.66k | case '2': |
918 | 6.66k | switch (statusCodeData[1]) |
919 | 6.66k | { |
920 | 5.34k | case '0': |
921 | 5.34k | switch (statusCodeData[2]) |
922 | 5.34k | { |
923 | 258 | case '0': |
924 | 258 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http200OK); |
925 | 780 | case '1': |
926 | 780 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http201Created); |
927 | 704 | case '2': |
928 | 704 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http202Accepted); |
929 | 738 | case '3': |
930 | 738 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http203NonAuthoritativeInformation); |
931 | 378 | case '4': |
932 | 378 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http204NoContent); |
933 | 823 | case '5': |
934 | 823 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http205ResetContent); |
935 | 511 | case '6': |
936 | 511 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http206PartialContent); |
937 | 536 | case '7': |
938 | 536 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http207MultiStatus); |
939 | 541 | case '8': |
940 | 541 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http208AlreadyReported); |
941 | 76 | default: |
942 | 76 | return HttpResponseLayer::HttpStatusCodeUnknown; |
943 | | |
944 | 5.34k | }; |
945 | |
|
946 | 0 | break; |
947 | 1.06k | case '2': |
948 | 1.06k | switch (statusCodeData[2]) |
949 | 1.06k | { |
950 | 832 | case '6': |
951 | 832 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http226IMUsed); |
952 | 231 | default: |
953 | 231 | return HttpResponseLayer::HttpStatusCodeUnknown; |
954 | 1.06k | }; |
955 | |
|
956 | 0 | break; |
957 | | |
958 | 260 | default: |
959 | 260 | return HttpResponseLayer::HttpStatusCodeUnknown; |
960 | | |
961 | 6.66k | }; |
962 | |
|
963 | 0 | break; |
964 | | |
965 | 8.96k | case '3': |
966 | 8.96k | switch (statusCodeData[1]) |
967 | 8.96k | { |
968 | 8.32k | case '0': |
969 | 8.32k | switch (statusCodeData[2]) |
970 | 8.32k | { |
971 | 854 | case '0': |
972 | 854 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http300MultipleChoices); |
973 | 815 | case '1': |
974 | 815 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http301MovedPermanently); |
975 | 741 | case '2': |
976 | 741 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http302); |
977 | 1.22k | case '3': |
978 | 1.22k | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http303SeeOther); |
979 | 394 | case '4': |
980 | 394 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http304NotModified); |
981 | 1.90k | case '5': |
982 | 1.90k | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http305UseProxy); |
983 | 894 | case '6': |
984 | 894 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http306SwitchProxy); |
985 | 770 | case '7': |
986 | 770 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http307TemporaryRedirect); |
987 | 466 | case '8': |
988 | 466 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http308PermanentRedirect); |
989 | 255 | default: |
990 | 255 | return HttpResponseLayer::HttpStatusCodeUnknown; |
991 | | |
992 | 8.32k | }; |
993 | |
|
994 | 0 | break; |
995 | | |
996 | 638 | default: |
997 | 638 | return HttpResponseLayer::HttpStatusCodeUnknown; |
998 | 8.96k | }; |
999 | |
|
1000 | 0 | break; |
1001 | | |
1002 | 36.6k | case '4': |
1003 | 36.6k | switch (statusCodeData[1]) |
1004 | 36.6k | { |
1005 | 9.71k | case '0': |
1006 | 9.71k | switch (statusCodeData[2]) |
1007 | 9.71k | { |
1008 | 750 | case '0': |
1009 | 750 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http400BadRequest); |
1010 | 538 | case '1': |
1011 | 538 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http401Unauthorized); |
1012 | 1.41k | case '2': |
1013 | 1.41k | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http402PaymentRequired); |
1014 | 596 | case '3': |
1015 | 596 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http403Forbidden); |
1016 | 1.70k | case '4': |
1017 | 1.70k | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http404NotFound); |
1018 | 820 | case '5': |
1019 | 820 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http405MethodNotAllowed); |
1020 | 676 | case '6': |
1021 | 676 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http406NotAcceptable); |
1022 | 968 | case '7': |
1023 | 968 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http407ProxyAuthenticationRequired); |
1024 | 984 | case '8': |
1025 | 984 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http408RequestTimeout); |
1026 | 745 | case '9': |
1027 | 745 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http409Conflict); |
1028 | 511 | default: |
1029 | 511 | return HttpResponseLayer::HttpStatusCodeUnknown; |
1030 | | |
1031 | 9.71k | }; |
1032 | |
|
1033 | 0 | break; |
1034 | | |
1035 | 9.54k | case '1': |
1036 | 9.54k | switch (statusCodeData[2]) |
1037 | 9.54k | { |
1038 | 901 | case '0': |
1039 | 901 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http410Gone); |
1040 | 827 | case '1': |
1041 | 827 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http411LengthRequired); |
1042 | 919 | case '2': |
1043 | 919 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http412PreconditionFailed); |
1044 | 848 | case '3': |
1045 | 848 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http413RequestEntityTooLarge); |
1046 | 1.55k | case '4': |
1047 | 1.55k | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http414RequestURITooLong); |
1048 | 551 | case '5': |
1049 | 551 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http415UnsupportedMediaType); |
1050 | 199 | case '6': |
1051 | 199 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http416RequestedRangeNotSatisfiable); |
1052 | 722 | case '7': |
1053 | 722 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http417ExpectationFailed); |
1054 | 930 | case '8': |
1055 | 930 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http418Imateapot); |
1056 | 1.65k | case '9': |
1057 | 1.65k | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http419AuthenticationTimeout); |
1058 | 429 | default: |
1059 | 429 | return HttpResponseLayer::HttpStatusCodeUnknown; |
1060 | | |
1061 | 9.54k | }; |
1062 | |
|
1063 | 0 | break; |
1064 | | |
1065 | 4.87k | case '2': |
1066 | 4.87k | switch (statusCodeData[2]) |
1067 | 4.87k | { |
1068 | 605 | case '0': |
1069 | 605 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http420); |
1070 | 593 | case '2': |
1071 | 593 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http422UnprocessableEntity); |
1072 | 450 | case '3': |
1073 | 450 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http423Locked); |
1074 | 624 | case '4': |
1075 | 624 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http424FailedDependency); |
1076 | 961 | case '6': |
1077 | 961 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http426UpgradeRequired); |
1078 | 548 | case '8': |
1079 | 548 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http428PreconditionRequired); |
1080 | 598 | case '9': |
1081 | 598 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http429TooManyRequests); |
1082 | 500 | default: |
1083 | 500 | return HttpResponseLayer::HttpStatusCodeUnknown; |
1084 | | |
1085 | 4.87k | }; |
1086 | |
|
1087 | 0 | break; |
1088 | | |
1089 | 1.87k | case '3': |
1090 | 1.87k | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http431RequestHeaderFieldsTooLarge); |
1091 | | |
1092 | 3.30k | case '4': |
1093 | 3.30k | switch (statusCodeData[2]) |
1094 | 3.30k | { |
1095 | 661 | case '0': |
1096 | 661 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http440LoginTimeout); |
1097 | 1.63k | case '4': |
1098 | 1.63k | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http444NoResponse); |
1099 | 552 | case '9': |
1100 | 552 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http449RetryWith); |
1101 | 457 | default: |
1102 | 457 | return HttpResponseLayer::HttpStatusCodeUnknown; |
1103 | 3.30k | }; |
1104 | |
|
1105 | 0 | break; |
1106 | | |
1107 | 1.85k | case '5': |
1108 | 1.85k | switch (statusCodeData[2]) |
1109 | 1.85k | { |
1110 | 703 | case '0': |
1111 | 703 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http450BlockedByWindowsParentalControls); |
1112 | 603 | case '1': |
1113 | 603 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http451); |
1114 | 544 | default: |
1115 | 544 | return HttpResponseLayer::HttpStatusCodeUnknown; |
1116 | 1.85k | }; |
1117 | |
|
1118 | 0 | break; |
1119 | | |
1120 | 4.51k | case '9': |
1121 | 4.51k | switch (statusCodeData[2]) |
1122 | 4.51k | { |
1123 | 478 | case '4': |
1124 | 478 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http494RequestHeaderTooLarge); |
1125 | 475 | case '5': |
1126 | 475 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http495CertError); |
1127 | 499 | case '6': |
1128 | 499 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http496NoCert); |
1129 | 350 | case '7': |
1130 | 350 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http497HTTPtoHTTPS); |
1131 | 1.07k | case '8': |
1132 | 1.07k | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http498TokenExpiredInvalid); |
1133 | 1.04k | case '9': |
1134 | 1.04k | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http499); |
1135 | 589 | default: |
1136 | 589 | return HttpResponseLayer::HttpStatusCodeUnknown; |
1137 | 4.51k | }; |
1138 | |
|
1139 | 0 | break; |
1140 | | |
1141 | 1.01k | default: |
1142 | 1.01k | return HttpResponseLayer::HttpStatusCodeUnknown; |
1143 | 36.6k | }; |
1144 | |
|
1145 | 0 | break; |
1146 | | |
1147 | 22.1k | case '5': |
1148 | 22.1k | switch (statusCodeData[1]) |
1149 | 22.1k | { |
1150 | 12.1k | case '0': |
1151 | 12.1k | switch (statusCodeData[2]) |
1152 | 12.1k | { |
1153 | 502 | case '0': |
1154 | 502 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http500InternalServerError); |
1155 | 1.29k | case '1': |
1156 | 1.29k | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http501NotImplemented); |
1157 | 167 | case '2': |
1158 | 167 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http502BadGateway); |
1159 | 1.16k | case '3': |
1160 | 1.16k | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http503ServiceUnavailable); |
1161 | 757 | case '4': |
1162 | 757 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http504GatewayTimeout); |
1163 | 1.47k | case '5': |
1164 | 1.47k | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http505HTTPVersionNotSupported); |
1165 | 785 | case '6': |
1166 | 785 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http506VariantAlsoNegotiates); |
1167 | 853 | case '7': |
1168 | 853 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http507InsufficientStorage); |
1169 | 507 | case '8': |
1170 | 507 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http508LoopDetected); |
1171 | 4.04k | case '9': |
1172 | 4.04k | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http509BandwidthLimitExceeded); |
1173 | 576 | default: |
1174 | 576 | return HttpResponseLayer::HttpStatusCodeUnknown; |
1175 | | |
1176 | 12.1k | }; |
1177 | |
|
1178 | 0 | break; |
1179 | | |
1180 | 2.48k | case '1': |
1181 | 2.48k | switch (statusCodeData[2]) |
1182 | 2.48k | { |
1183 | 650 | case '0': |
1184 | 650 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http510NotExtended); |
1185 | 1.50k | case '1': |
1186 | 1.50k | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http511NetworkAuthenticationRequired); |
1187 | 332 | default: |
1188 | 332 | return HttpResponseLayer::HttpStatusCodeUnknown; |
1189 | 2.48k | }; |
1190 | |
|
1191 | 0 | break; |
1192 | | |
1193 | 3.66k | case '2': |
1194 | 3.66k | switch (statusCodeData[2]) |
1195 | 3.66k | { |
1196 | 489 | case '0': |
1197 | 489 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http520OriginError); |
1198 | 673 | case '1': |
1199 | 673 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http521WebServerIsDown); |
1200 | 585 | case '2': |
1201 | 585 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http522ConnectionTimedOut); |
1202 | 410 | case '3': |
1203 | 410 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http523ProxyDeclinedRequest); |
1204 | 952 | case '4': |
1205 | 952 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http524aTimeoutOccurred); |
1206 | 558 | default: |
1207 | 558 | return HttpResponseLayer::HttpStatusCodeUnknown; |
1208 | 3.66k | }; |
1209 | |
|
1210 | 0 | break; |
1211 | | |
1212 | 2.65k | case '9': |
1213 | 2.65k | switch (statusCodeData[2]) |
1214 | 2.65k | { |
1215 | 1.42k | case '8': |
1216 | 1.42k | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http598NetworkReadTimeoutError); |
1217 | 585 | case '9': |
1218 | 585 | return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, HttpResponseLayer::Http599NetworkConnectTimeoutError); |
1219 | 648 | default: |
1220 | 648 | return HttpResponseLayer::HttpStatusCodeUnknown; |
1221 | 2.65k | }; |
1222 | |
|
1223 | 0 | break; |
1224 | | |
1225 | 1.19k | default: |
1226 | 1.19k | return HttpResponseLayer::HttpStatusCodeUnknown; |
1227 | 22.1k | }; |
1228 | |
|
1229 | 0 | break; |
1230 | | |
1231 | 2.12k | default: |
1232 | 2.12k | return HttpResponseLayer::HttpStatusCodeUnknown; |
1233 | 79.8k | } |
1234 | | |
1235 | 0 | return HttpResponseLayer::HttpStatusCodeUnknown; |
1236 | 79.8k | } |
1237 | | |
1238 | | HttpResponseFirstLine::HttpResponseFirstLine(HttpResponseLayer* httpResponse) : m_HttpResponse(httpResponse) |
1239 | 13.3k | { |
1240 | 13.3k | m_Version = parseVersion((char*)m_HttpResponse->m_Data, m_HttpResponse->getDataLen()); |
1241 | 13.3k | if (m_Version == HttpVersionUnknown) |
1242 | 0 | { |
1243 | 0 | m_StatusCode = HttpResponseLayer::HttpStatusCodeUnknown; |
1244 | 0 | } |
1245 | 13.3k | else |
1246 | 13.3k | { |
1247 | 13.3k | m_StatusCode = parseStatusCode((char*)m_HttpResponse->m_Data, m_HttpResponse->getDataLen()); |
1248 | 13.3k | } |
1249 | | |
1250 | | |
1251 | 13.3k | char* endOfFirstLine; |
1252 | 13.3k | if ((endOfFirstLine = (char*)memchr((char*)(m_HttpResponse->m_Data), '\n', m_HttpResponse->m_DataLen)) != NULL) |
1253 | 2.87k | { |
1254 | 2.87k | m_FirstLineEndOffset = endOfFirstLine - (char*)m_HttpResponse->m_Data + 1; |
1255 | 2.87k | m_IsComplete = true; |
1256 | 2.87k | } |
1257 | 10.5k | else |
1258 | 10.5k | { |
1259 | 10.5k | m_FirstLineEndOffset = m_HttpResponse->getDataLen(); |
1260 | 10.5k | m_IsComplete = false; |
1261 | 10.5k | } |
1262 | | |
1263 | 13.3k | if (Logger::getInstance().isDebugEnabled(PacketLogModuleHttpLayer)) |
1264 | 0 | { |
1265 | 0 | std::string version = (m_Version == HttpVersionUnknown ? "Unknown" : VersionEnumToString[m_Version]); |
1266 | 0 | int statusCode = (m_StatusCode == HttpResponseLayer::HttpStatusCodeUnknown ? 0 : StatusCodeEnumToInt[m_StatusCode]); |
1267 | 0 | PCPP_LOG_DEBUG("Version='" << version << "'; Status code=" << statusCode << " '" << getStatusCodeString() << "'"); |
1268 | 0 | } |
1269 | 13.3k | } |
1270 | | |
1271 | | |
1272 | | HttpResponseFirstLine::HttpResponseFirstLine(HttpResponseLayer* httpResponse, HttpVersion version, HttpResponseLayer::HttpResponseStatusCode statusCode, std::string statusCodeString) |
1273 | 0 | { |
1274 | 0 | if (statusCode == HttpResponseLayer::HttpStatusCodeUnknown) |
1275 | 0 | { |
1276 | 0 | m_Exception.setMessage("Status code supplied was HttpStatusCodeUnknown"); |
1277 | 0 | throw m_Exception; |
1278 | 0 | } |
1279 | | |
1280 | 0 | if (version == HttpVersionUnknown) |
1281 | 0 | { |
1282 | 0 | m_Exception.setMessage("Version supplied was HttpVersionUnknown"); |
1283 | 0 | throw m_Exception; |
1284 | 0 | } |
1285 | | |
1286 | 0 | m_HttpResponse = httpResponse; |
1287 | |
|
1288 | 0 | m_StatusCode = statusCode; |
1289 | 0 | m_Version = version; |
1290 | |
|
1291 | 0 | std::ostringstream statusCodeAsString; |
1292 | 0 | statusCodeAsString << StatusCodeEnumToInt[m_StatusCode]; |
1293 | 0 | if (statusCodeString == "") |
1294 | 0 | statusCodeString = StatusCodeEnumToString[m_StatusCode]; |
1295 | 0 | std::string firstLine = "HTTP/" + VersionEnumToString[m_Version] + " " + statusCodeAsString.str() + " " + statusCodeString + "\r\n"; |
1296 | |
|
1297 | 0 | m_FirstLineEndOffset = firstLine.length(); |
1298 | |
|
1299 | 0 | m_HttpResponse->m_DataLen = firstLine.length(); |
1300 | 0 | m_HttpResponse->m_Data = new uint8_t[m_HttpResponse->m_DataLen]; |
1301 | 0 | memcpy(m_HttpResponse->m_Data, firstLine.c_str(), m_HttpResponse->m_DataLen); |
1302 | |
|
1303 | 0 | m_IsComplete = true; |
1304 | 0 | } |
1305 | | |
1306 | | HttpVersion HttpResponseFirstLine::parseVersion(char* data, size_t dataLen) |
1307 | 111k | { |
1308 | 111k | if (dataLen < 8) // "HTTP/x.y" |
1309 | 362 | { |
1310 | 362 | PCPP_LOG_DEBUG("HTTP response length < 8, cannot identify version"); |
1311 | 362 | return HttpVersionUnknown; |
1312 | 362 | } |
1313 | | |
1314 | 110k | if (data[0] != 'H' || data[1] != 'T' || data[2] != 'T' || data[3] != 'P' || data[4] != '/') |
1315 | 11.3k | { |
1316 | 11.3k | PCPP_LOG_DEBUG("HTTP response does not begin with 'HTTP/'"); |
1317 | 11.3k | return HttpVersionUnknown; |
1318 | 11.3k | } |
1319 | | |
1320 | 99.5k | char* verPos = data + 5; |
1321 | 99.5k | switch (verPos[0]) |
1322 | 99.5k | { |
1323 | 22.8k | case '0': |
1324 | 22.8k | if (verPos[1] == '.' && verPos[2] == '9') |
1325 | 20.6k | return ZeroDotNine; |
1326 | 2.11k | else |
1327 | 2.11k | return HttpVersionUnknown; |
1328 | 0 | break; |
1329 | | |
1330 | 75.5k | case '1': |
1331 | 75.5k | if (verPos[1] == '.' && verPos[2] == '0') |
1332 | 57.2k | return OneDotZero; |
1333 | 18.2k | else if (verPos[1] == '.' && verPos[2] == '1') |
1334 | 15.4k | return OneDotOne; |
1335 | 2.81k | else |
1336 | 2.81k | return HttpVersionUnknown; |
1337 | 0 | break; |
1338 | | |
1339 | 1.21k | default: |
1340 | 1.21k | return HttpVersionUnknown; |
1341 | 99.5k | } |
1342 | 99.5k | } |
1343 | | |
1344 | | } // namespace pcpp |