Coverage Report

Created: 2025-07-11 07:47

/src/PcapPlusPlus/Packet++/header/HttpLayer.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include "DeprecationUtils.h"
4
#include "TextBasedProtocol.h"
5
#include <string>
6
#include <exception>
7
8
/// @file
9
10
/// @namespace pcpp
11
/// @brief The main namespace for the PcapPlusPlus lib
12
namespace pcpp
13
{
14
  /// An enum for HTTP version
15
  enum HttpVersion
16
  {
17
    /// HTTP/0.9
18
    ZeroDotNine,
19
    /// HTTP/1.0
20
    OneDotZero,
21
    /// HTTP/1.1
22
    OneDotOne,
23
    /// Unknown HTTP version
24
    HttpVersionUnknown
25
  };
26
27
  // some popular HTTP fields
28
29
  /// Host field
30
0
#define PCPP_HTTP_HOST_FIELD "Host"
31
  /// Connection field
32
#define PCPP_HTTP_CONNECTION_FIELD "Connection"
33
  /// User-Agent field
34
#define PCPP_HTTP_USER_AGENT_FIELD "User-Agent"
35
  /// Referer field
36
#define PCPP_HTTP_REFERER_FIELD "Referer"
37
  /// Accept field
38
#define PCPP_HTTP_ACCEPT_FIELD "Accept"
39
  /// Accept-Encoding field
40
#define PCPP_HTTP_ACCEPT_ENCODING_FIELD "Accept-Encoding"
41
  /// Accept-Language field
42
#define PCPP_HTTP_ACCEPT_LANGUAGE_FIELD "Accept-Language"
43
  /// Cookie field
44
#define PCPP_HTTP_COOKIE_FIELD "Cookie"
45
  /// Content-Length field
46
0
#define PCPP_HTTP_CONTENT_LENGTH_FIELD "Content-Length"
47
  /// Content-Encoding field
48
#define PCPP_HTTP_CONTENT_ENCODING_FIELD "Content-Encoding"
49
  /// Content-Type field
50
#define PCPP_HTTP_CONTENT_TYPE_FIELD "Content-Type"
51
  /// Transfer-Encoding field
52
#define PCPP_HTTP_TRANSFER_ENCODING_FIELD "Transfer-Encoding"
53
  /// Server field
54
#define PCPP_HTTP_SERVER_FIELD "Server"
55
56
  // -------- classes to be defined later -----------------
57
58
  class HttpRequestFirstLine;
59
  class HttpResponseFirstLine;
60
61
  // -------- Class HttpMessage -----------------
62
63
  /// @class HttpMessage
64
  /// Represents a general HTTP message. It's an abstract class and cannot be instantiated. It's inherited by
65
  /// HttpRequestLayer and HttpResponseLayer
66
  class HttpMessage : public TextBasedProtocolMessage
67
  {
68
  public:
69
    ~HttpMessage() override = default;
70
71
    /// A static method that checks whether the port is considered as HTTP
72
    /// @param[in] port The port number to be checked
73
    /// @return True if the port matches those associated with the HTTP protocol
74
    static bool isHttpPort(uint16_t port)
75
286k
    {
76
286k
      return port == 80 || port == 8080;
77
286k
    }
78
79
    // overridden methods
80
81
    HeaderField* addField(const std::string& fieldName, const std::string& fieldValue) override;
82
    HeaderField* addField(const HeaderField& newField) override;
83
    HeaderField* insertField(HeaderField* prevField, const std::string& fieldName,
84
                             const std::string& fieldValue) override;
85
    HeaderField* insertField(HeaderField* prevField, const HeaderField& newField) override;
86
87
    OsiModelLayer getOsiModelLayer() const override
88
1.19k
    {
89
1.19k
      return OsiModelApplicationLayer;
90
1.19k
    }
91
92
  protected:
93
    HttpMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ProtocolType protocol)
94
6.19k
        : TextBasedProtocolMessage(data, dataLen, prevLayer, packet, protocol)
95
6.19k
    {}
96
0
    HttpMessage() : TextBasedProtocolMessage()
97
0
    {}
98
0
    HttpMessage(const HttpMessage& other) : TextBasedProtocolMessage(other)
99
0
    {}
100
    HttpMessage& operator=(const HttpMessage& other)
101
0
    {
102
0
      TextBasedProtocolMessage::operator=(other);
103
0
      return *this;
104
0
    }
105
106
    // implementation of abstract methods
107
    char getHeaderFieldNameValueSeparator() const override
108
6.19k
    {
109
6.19k
      return ':';
110
6.19k
    }
111
    bool spacesAllowedBetweenHeaderFieldNameAndValue() const override
112
6.19k
    {
113
6.19k
      return true;
114
6.19k
    }
115
  };
116
117
  // -------- Class HttpRequestLayer -----------------
118
119
  /// @class HttpRequestLayer
120
  /// Represents an HTTP request header and inherits all basic functionality of HttpMessage and
121
  /// TextBasedProtocolMessage. The functionality that is added for this class is the HTTP first line concept. An HTTP
122
  /// request has the following first line: <i>GET /bla/blabla.asp HTTP/1.1</i> Since it's not an "ordinary" HTTP
123
  /// field, it requires a special treatment and gets a class of it's own: HttpRequestFirstLine. Unlike most L2-4
124
  /// protocols, an HTTP request header can spread over more than 1 packet. PcapPlusPlus currently doesn't support a
125
  /// header that is spread over more than 1 packet so in such cases: 1) only the first packet will be parsed as
126
  /// HttpRequestLayer (the other packets won't be recognized as HttpRequestLayer) and 2) the HTTP header for the
127
  /// first packet won't be complete (as it continues in the following packets), this why PcapPlusPlus can indicate
128
  /// that HTTP request header is complete or not(doesn't end with "\r\n\r\n" or "\n\n") using
129
  /// HttpMessage#isHeaderComplete()
130
  class HttpRequestLayer : public HttpMessage
131
  {
132
    friend class HttpRequestFirstLine;
133
134
  public:
135
    /// HTTP request methods
136
    enum HttpMethod
137
    {
138
      /// GET
139
      HttpGET,
140
      /// HEAD
141
      HttpHEAD,
142
      /// POST
143
      HttpPOST,
144
      /// PUT
145
      HttpPUT,
146
      /// DELETE
147
      HttpDELETE,
148
      /// TRACE
149
      HttpTRACE,
150
      /// OPTIONS
151
      HttpOPTIONS,
152
      /// CONNECT
153
      HttpCONNECT,
154
      /// PATCH
155
      HttpPATCH,
156
      /// Unknown HTTP method
157
      HttpMethodUnknown
158
    };
159
160
    /// A constructor that creates the layer from an existing packet raw data
161
    /// @param[in] data A pointer to the raw data
162
    /// @param[in] dataLen Size of the data in bytes
163
    /// @param[in] prevLayer A pointer to the previous layer
164
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
165
    HttpRequestLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
166
167
    /// A constructor that allocates a new HTTP request header with only the first line filled. Object will be
168
    /// created without further fields. The user can then add fields using addField() methods
169
    /// @param[in] method The HTTP method used in this HTTP request
170
    /// @param[in] uri The URI of the first line
171
    /// @param[in] version HTTP version to be used in this request
172
    HttpRequestLayer(HttpMethod method, const std::string& uri, HttpVersion version);
173
174
    ~HttpRequestLayer() override;
175
176
    /// A copy constructor for this layer. This copy constructor inherits base copy constructor
177
    /// HttpMessage#HttpMessage() and add the functionality of copying the first line as well
178
    /// @param[in] other The instance to copy from
179
    HttpRequestLayer(const HttpRequestLayer& other);
180
181
    /// An assignment operator overload for this layer. This method inherits base assignment operator
182
    /// HttpMessage#operator=() and add the functionality of copying the first line as well
183
    /// @param[in] other The instance to copy from
184
    /// @return A reference to the assignee
185
    HttpRequestLayer& operator=(const HttpRequestLayer& other);
186
187
    /// @return A pointer to the first line instance for this message
188
    HttpRequestFirstLine* getFirstLine() const
189
0
    {
190
0
      return m_FirstLine;
191
0
    }
192
193
    /// The URL is hostname+uri. So given the following URL, for example: "www.cnn.com/main.html", the hostname is
194
    /// "www.cnn.com" and the URI is "/.main.html". URI and hostname are split to 2 different places inside the HTTP
195
    /// request packet: URI is in the first line and hostname is in "HOST" field. This methods concatenates the
196
    /// hostname and URI to the full URL
197
    /// @return The URL of the HTTP request message
198
    std::string getUrl() const;
199
200
    // implement Layer's abstract methods
201
    std::string toString() const override;
202
203
  private:
204
    HttpRequestFirstLine* m_FirstLine;
205
  };
206
207
  // -------- Class HttpResponseStatusCode -----------------
208
209
  /// @struct HttpResponseStatusCode
210
  /// @brief The enum wrapper class of HTTP response status codes
211
  class HttpResponseStatusCode
212
  {
213
  public:
214
    /// @brief Define enum types and the corresponding int values
215
    enum Value : int
216
    {
217
      /// 100 Continue
218
      Http100Continue = 100,
219
      /// 101 Switching Protocols
220
      Http101SwitchingProtocols = 101,
221
      /// 102 Processing
222
      Http102Processing = 102,
223
      /// 103 Early Hints
224
      Http103EarlyHints = 103,
225
      /// 104-199 Unassigned
226
227
      /// 200 OK
228
      Http200OK = 200,
229
      /// 201 Created
230
      Http201Created = 201,
231
      /// 202 Accepted
232
      Http202Accepted = 202,
233
      /// 203 Non-Authoritative Information
234
      Http203NonAuthoritativeInformation = 203,
235
      /// 204 No Content
236
      Http204NoContent = 204,
237
      /// 205 Reset Content
238
      Http205ResetContent = 205,
239
      /// 206 Partial Content
240
      Http206PartialContent = 206,
241
      /// 207 Multi-Status
242
      Http207MultiStatus = 207,
243
      /// 208 Already Reported
244
      Http208AlreadyReported = 208,
245
      /// 209-225 Unassigned
246
      /// 226 IM Used
247
      Http226IMUsed = 226,
248
      /// 227-299 Unassigned
249
250
      /// 300 Multiple Choices
251
      Http300MultipleChoices = 300,
252
      /// 301 Moved Permanently
253
      Http301MovedPermanently = 301,
254
      /// 302 (various messages)
255
      Http302 = 302,
256
      /// 303 See Other
257
      Http303SeeOther = 303,
258
      /// 304 Not Modified
259
      Http304NotModified = 304,
260
      /// 305 Use Proxy
261
      Http305UseProxy = 305,
262
      /// 306 Switch Proxy
263
      Http306SwitchProxy = 306,
264
      /// 307 Temporary Redirect
265
      Http307TemporaryRedirect = 307,
266
      /// 308 Permanent Redirect,
267
      Http308PermanentRedirect = 308,
268
      /// 309-399 Unassigned
269
270
      /// 400 Bad Request
271
      Http400BadRequest = 400,
272
      /// 401 Unauthorized
273
      Http401Unauthorized = 401,
274
      /// 402 Payment Required
275
      Http402PaymentRequired = 402,
276
      /// 403 Forbidden
277
      Http403Forbidden = 403,
278
      /// 404 Not Found
279
      Http404NotFound = 404,
280
      /// 405 Method Not Allowed
281
      Http405MethodNotAllowed = 405,
282
      /// 406 Not Acceptable
283
      Http406NotAcceptable = 406,
284
      /// 407 Proxy Authentication Required
285
      Http407ProxyAuthenticationRequired = 407,
286
      /// 408 Request Timeout
287
      Http408RequestTimeout = 408,
288
      /// 409 Conflict
289
      Http409Conflict = 409,
290
      /// 410 Gone
291
      Http410Gone = 410,
292
      /// 411 Length Required
293
      Http411LengthRequired = 411,
294
      /// 412 Precondition Failed
295
      Http412PreconditionFailed = 412,
296
      /// 413 RequestEntity Too Large
297
      Http413RequestEntityTooLarge = 413,
298
      /// 414 Request-URI Too Long
299
      Http414RequestURITooLong = 414,
300
      /// 415 Unsupported Media Type
301
      Http415UnsupportedMediaType = 415,
302
      /// 416 Requested Range Not Satisfiable
303
      Http416RequestedRangeNotSatisfiable = 416,
304
      /// 417 Expectation Failed
305
      Http417ExpectationFailed = 417,
306
      /// 418 I'm a teapot
307
      Http418ImATeapot = 418,
308
      /// 419 Authentication Timeout
309
      Http419AuthenticationTimeout = 419,
310
      /// 420 (various messages)
311
      Http420 = 420,
312
      /// 421 Misdirected Request
313
      Http421MisdirectedRequest = 421,
314
      /// 422 Unprocessable Entity
315
      Http422UnprocessableEntity = 422,
316
      /// 423 Locked
317
      Http423Locked = 423,
318
      /// 424 Failed Dependency
319
      Http424FailedDependency = 424,
320
      /// 425 Too Early
321
      Http425TooEarly = 425,
322
      /// 426 Upgrade Required
323
      Http426UpgradeRequired = 426,
324
      /// 427 Unassigned
325
      /// 428 Precondition Required
326
      Http428PreconditionRequired = 428,
327
      /// 429 Too Many Requests
328
      Http429TooManyRequests = 429,
329
      /// 430 Unassigned
330
      /// 431 Request Header Fields Too Large
331
      Http431RequestHeaderFieldsTooLarge = 431,
332
      /// 432-439 unassigned
333
      /// 440 Login Timeout
334
      Http440LoginTimeout = 440,
335
      /// 441-443 unassigned
336
      /// 444 No Response
337
      Http444NoResponse = 444,
338
      /// 445-448 unassigned
339
      /// 449 Retry With
340
      Http449RetryWith = 449,
341
      /// 450 Blocked by Windows Parental Controls
342
      Http450BlockedByWindowsParentalControls = 450,
343
      /// 451 (various messages)
344
      Http451 = 451,
345
      /// 452-493 unassigned
346
      /// 494 Request Header Too Large
347
      Http494RequestHeaderTooLarge = 494,
348
      /// 495 Cert Error
349
      Http495CertError = 495,
350
      /// 496 No Cert
351
      Http496NoCert = 496,
352
      /// 497 HTTP to HTTPS
353
      Http497HTTPtoHTTPS = 497,
354
      /// 498 Token expired/invalid
355
      Http498TokenExpiredInvalid = 498,
356
      /// 499 (various messages)
357
      Http499 = 499,
358
359
      /// 500 Internal Server Error
360
      Http500InternalServerError = 500,
361
      /// 501 Not Implemented
362
      Http501NotImplemented = 501,
363
      /// 502 Bad Gateway
364
      Http502BadGateway = 502,
365
      /// 503 Service Unavailable
366
      Http503ServiceUnavailable = 503,
367
      /// 504 Gateway Timeout
368
      Http504GatewayTimeout = 504,
369
      /// 505 HTTP Version Not Supported
370
      Http505HTTPVersionNotSupported = 505,
371
      /// 506 Variant Also Negotiates
372
      Http506VariantAlsoNegotiates = 506,
373
      /// 507 Insufficient Storage
374
      Http507InsufficientStorage = 507,
375
      /// 508 Loop Detected
376
      Http508LoopDetected = 508,
377
      /// 509 Bandwidth Limit Exceeded
378
      Http509BandwidthLimitExceeded = 509,
379
      /// 510 Not Extended
380
      Http510NotExtended = 510,
381
      /// 511 Network Authentication Required
382
      Http511NetworkAuthenticationRequired = 511,
383
      /// 512-519 unassigned
384
      /// 520 Origin Error
385
      Http520OriginError = 520,
386
      /// 521 Web server is down
387
      Http521WebServerIsDown = 521,
388
      /// 522 Connection timed out
389
      Http522ConnectionTimedOut = 522,
390
      /// 523 Proxy Declined Request
391
      Http523ProxyDeclinedRequest = 523,
392
      /// 524 A timeout occurred
393
      Http524aTimeoutOccurred = 524,
394
      /// 525-597 unassigned
395
      /// 598 Network read timeout error
396
      Http598NetworkReadTimeoutError = 598,
397
      /// 599 Network connect timeout error
398
      Http599NetworkConnectTimeoutError = 599,
399
400
      // clang-format off
401
      /// Unknown status code
402
      HttpStatus1xxCodeUnknown = 900001, // 1xx: Informational - Request received, continuing process
403
      HttpStatus2xxCodeUnknown = 900002, // 2xx: Success - The action was successfully received, understood, and accepted
404
      HttpStatus3xxCodeUnknown = 900003, // 3xx: Redirection - Further action must be taken in order to complete the request
405
      HttpStatus4xxCodeUnknown = 900004, // 4xx: Client Error - The request contains bad syntax or cannot be fulfilled
406
      HttpStatus5xxCodeUnknown = 900005, // 5xx: Server Error - The server failed to fulfill an apparently valid request
407
      HttpStatusCodeUnknown = 999999,    // other arbitrary number
408
      // clang-format on
409
    };
410
411
3.70k
    HttpResponseStatusCode() = default;
412
413
    // cppcheck-suppress noExplicitConstructor
414
    /// @brief Construct HttpResponseStatusCode from Value enum
415
    /// @param[in] statusCode the status code enum
416
389
    HttpResponseStatusCode(Value statusCode) : m_Value(statusCode)
417
389
    {}
418
419
    /// @brief Construct HttpResponseStatusCode from the code number and the customized message
420
    /// @param[in] statusCodeNumber the status code in number, e.g. 200, 404
421
    /// @param[in] statusMessage the status message, optional, leave empty to use a default message
422
    explicit HttpResponseStatusCode(const int& statusCodeNumber, const std::string& statusMessage = "");
423
424
    /// @brief Construct HttpResponseStatusCode from Value enum and the customized message
425
    /// @param[in] statusCode the status code enum
426
    /// @param[in] statusMessage the customized status message, optional
427
    explicit HttpResponseStatusCode(const Value& statusCode, const std::string& statusMessage);
428
429
    // Allow switch and comparisons.
430
    operator Value() const
431
7.58k
    {
432
7.58k
      return m_Value;
433
7.58k
    }
434
    // Prevent usage: if(httpResponseStatusCode)
435
    explicit operator bool() const = delete;
436
437
    /// @brief get status code number as string
438
    std::string toString() const
439
0
    {
440
0
      return std::to_string(m_Value);
441
0
    }
442
443
    /// @brief get status code number as int
444
    int toInt() const
445
0
    {
446
0
      return static_cast<int>(m_Value);
447
0
    }
448
449
    /// @brief get status code message, e.g. "OK", "Not Found"
450
    std::string getMessage() const;
451
    /// @return If this HttpResponseStatusCode a valid code
452
    /// @note Any unknown or error code has an extreme large enum value
453
    bool isUnsupportedCode() const
454
3.82k
    {
455
3.82k
      return m_Value > 599;
456
3.82k
    }
457
458
  private:
459
    Value m_Value = HttpStatusCodeUnknown;
460
    std::string m_CustomizedMessage;
461
  };
462
463
  // -------- Class HttpResponseLayer -----------------
464
465
  /// @class HttpResponseLayer
466
  /// Represents an HTTP response header and inherits all basic functionality of HttpMessage and
467
  /// TextBasedProtocolMessage. The functionality that is added for this class is the HTTP first line concept. An HTTP
468
  /// response has the following first line: <i>200 OK HTTP/1.1</i> Since it's not an "ordinary" HTTP field, it
469
  /// requires a special treatment and gets a class of it's own: HttpResponseFirstLine. Unlike most L2-4 protocols, an
470
  /// HTTP response header can spread over more than 1 packet. PcapPlusPlus currently doesn't support a header that is
471
  /// spread over more than 1 packet so in such cases: 1) only the first packet will be parsed as HttpResponseLayer
472
  /// (the other packets won't be recognized as HttpResponseLayer) and 2) the HTTP header for the first packet won't
473
  /// be complete (as it continues in the following packets), this why PcapPlusPlus can indicate that HTTP response
474
  /// header is complete or not (doesn't end with "\r\n\r\n" or "\n\n") using HttpMessage#isHeaderComplete()
475
  class HttpResponseLayer : public HttpMessage
476
  {
477
    friend class HttpResponseFirstLine;
478
479
  public:
480
    // backward compatibility
481
    using HttpResponseStatusCode = pcpp::HttpResponseStatusCode;
482
483
    /// A constructor that creates the layer from an existing packet raw data
484
    /// @param[in] data A pointer to the raw data
485
    /// @param[in] dataLen Size of the data in bytes
486
    /// @param[in] prevLayer A pointer to the previous layer
487
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
488
    HttpResponseLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
489
490
    /// A constructor that allocates a new HTTP response header with only the first line filled. Object will be
491
    /// created without further fields. The user can then add fields using addField() methods
492
    /// @param[in] version HTTP version to be used
493
    /// @param[in] statusCode Status code to be used
494
    /// @param[in] statusCodeString Most status codes have their default string, e.g 200 is usually "OK", 404 is
495
    /// usually "Not Found", etc. But the user can set a non-default status code string and it will be written in
496
    /// the header first line. Empty string ("") means using the default status code string
497
    /// @deprecated Use other constructors instead.
498
    PCPP_DEPRECATED("Use other constructors instead")
499
    explicit HttpResponseLayer(HttpVersion version, const HttpResponseStatusCode& statusCode,
500
                               const std::string& statusCodeString);
501
502
    /// A constructor that allocates a new HTTP response header with only the first line filled. Object will be
503
    /// created without further fields. The user can then add fields using addField() methods
504
    /// @param[in] version HTTP version to be used
505
    /// @param[in] statusCode Status code to be used
506
    explicit HttpResponseLayer(HttpVersion version, const HttpResponseStatusCode& statusCode);
507
508
    ~HttpResponseLayer() override;
509
510
    /// A copy constructor for this layer. This copy constructor inherits base copy constructor
511
    /// HttpMessage#HttpMessage() and adds the functionality of copying the first line as well
512
    /// @param[in] other The instance to copy from
513
    HttpResponseLayer(const HttpResponseLayer& other);
514
515
    /// An assignment operator overload for this layer. This method inherits base assignment operator
516
    /// HttpMessage#operator=() and adds the functionality of copying the first line as well
517
    /// @param[in] other The instance to copy from
518
    /// @return A reference to the assignee
519
    HttpResponseLayer& operator=(const HttpResponseLayer& other);
520
521
    /// @return A pointer to the first line instance for this message
522
    HttpResponseFirstLine* getFirstLine() const
523
0
    {
524
0
      return m_FirstLine;
525
0
    }
526
527
    /// The length of the body of many HTTP response messages is determined by a HTTP header field called
528
    /// "Content-Length". This method sets The content-length field value. The method supports several cases:
529
    ///   - If the "Content-Length" field exists - the method will only replace the existing value with the new
530
    ///   value
531
    ///   - If the "Content-Length" field doesn't exist - the method will create this field and put the value in it.
532
    /// Here are also 2 cases:
533
    ///   - If prevFieldName is specified - the new "Content-Length" field will be created after it
534
    ///   - If prevFieldName isn't specified or doesn't exist - the new "Content-Length" field will be created as
535
    ///   the last field before end-of-header field
536
    ///
537
    /// @param[in] contentLength The content length value to set
538
    /// @param[in] prevFieldName Optional field, if specified and "Content-Length" field doesn't exist, it will be
539
    /// created after it
540
    /// @return A pointer to the "Content-Length" field, or nullptr if creation failed for some reason
541
    HeaderField* setContentLength(int contentLength, const std::string& prevFieldName = "");
542
543
    /// The length of the body of many HTTP response messages is determined by a HTTP header field called
544
    /// "Content-Length". This method parses this field, extracts its value and return it. If this field doesn't
545
    /// exist the method will return 0
546
    /// @return HTTP response body length determined by "Content-Length" field
547
    int getContentLength() const;
548
549
    // implement Layer's abstract methods
550
551
    std::string toString() const override;
552
553
  private:
554
    HttpResponseFirstLine* m_FirstLine;
555
  };
556
557
  // -------- Class HttpRequestFirstLine -----------------
558
559
  /// @class HttpRequestFirstLine
560
  /// Represents an HTTP request header first line. The first line includes 3 parameters: HTTP method (e.g GET, POST,
561
  /// etc.), URI (e.g /main/index.html) and HTTP version (e.g HTTP/1.1). All these parameters are included in this
562
  /// class, and the user can retrieve or set them. This class cannot be instantiated by users, it's created inside
563
  /// HttpRequestLayer and user can get a pointer to an instance of it. All "get" methods of this class will retrieve
564
  /// the actual data of the HTTP request and the "set" methods will change the packet data. Since HTTP is a textual
565
  /// protocol, most fields aren't of fixed size and this also applies to the first line parameters. So most "set"
566
  /// methods of this class need in most cases to shorten or extend the data in HttpRequestLayer. These methods will
567
  /// return a false value if this action failed
568
  class HttpRequestFirstLine
569
  {
570
    friend class HttpRequestLayer;
571
572
  public:
573
    /// @return The HTTP method
574
    HttpRequestLayer::HttpMethod getMethod() const
575
0
    {
576
0
      return m_Method;
577
0
    }
578
579
    /// Set the HTTP method
580
    /// @param[in] newMethod The method to set
581
    /// @return False if newMethod is HttpRequestLayer#HttpMethodUnknown or if shortening/extending the
582
    /// HttpRequestLayer data failed. True otherwise
583
    bool setMethod(HttpRequestLayer::HttpMethod newMethod);
584
585
    /// @return A copied version of the URI (notice changing the return value won't change the actual data of the
586
    /// packet)
587
    std::string getUri() const;
588
589
    /// Set the URI
590
    /// @param[in] newUri The URI to set
591
    /// @return False if shortening/extending the HttpRequestLayer data failed. True otherwise
592
    bool setUri(std::string newUri);
593
594
    /// @return The HTTP version
595
    HttpVersion getVersion() const
596
0
    {
597
0
      return m_Version;
598
0
    }
599
600
    /// Set the HTTP version. This method doesn't return a value since all supported HTTP versions are of the same
601
    /// size (HTTP/0.9, HTTP/1.0, HTTP/1.1)
602
    /// @param[in] newVersion The HTTP version to set
603
    void setVersion(HttpVersion newVersion);
604
605
    /// A static method for parsing the HTTP method out of raw data
606
    /// @param[in] data The raw data
607
    /// @param[in] dataLen The raw data length
608
    /// @return The parsed HTTP method
609
    static HttpRequestLayer::HttpMethod parseMethod(const char* data, size_t dataLen);
610
611
    /// @return The size in bytes of the HTTP first line
612
    int getSize() const
613
3.44k
    {
614
3.44k
      return m_FirstLineEndOffset;
615
3.44k
    }
616
617
    /// As explained in HttpRequestLayer, an HTTP header can spread over more than 1 packet, so when looking at a
618
    /// single packet the header can be partial. Same goes for the first line - it can spread over more than 1
619
    /// packet. This method returns an indication whether the first line is partial
620
    /// @return False if the first line is partial, true if it's complete
621
    bool isComplete() const
622
0
    {
623
0
      return m_IsComplete;
624
0
    }
625
626
    /// @class HttpRequestFirstLineException
627
    /// This exception can be thrown while constructing HttpRequestFirstLine (the constructor is private, so the
628
    /// construction happens only in HttpRequestLayer). This kind of exception will be thrown if trying to construct
629
    /// with HTTP method of HttpRequestLayer#HttpMethodUnknown or with undefined HTTP version ::HttpVersionUnknown
630
    class HttpRequestFirstLineException : public std::exception
631
    {
632
    public:
633
      ~HttpRequestFirstLineException() noexcept
634
2.48k
      {}
635
      void setMessage(const std::string& message)
636
0
      {
637
0
        m_Message = message;
638
0
      }
639
      virtual const char* what() const noexcept
640
0
      {
641
0
        return m_Message.c_str();
642
0
      }
643
644
    private:
645
      std::string m_Message;
646
    };
647
648
  private:
649
    HttpRequestFirstLine(HttpRequestLayer* httpRequest);
650
    HttpRequestFirstLine(HttpRequestLayer* httpRequest, HttpRequestLayer::HttpMethod method, HttpVersion version,
651
                         const std::string& uri = "/");
652
653
    void parseVersion();
654
655
    HttpRequestLayer* m_HttpRequest;
656
    HttpRequestLayer::HttpMethod m_Method;
657
    HttpVersion m_Version;
658
    int m_VersionOffset;
659
    int m_UriOffset;
660
    int m_FirstLineEndOffset;
661
    bool m_IsComplete;
662
    HttpRequestFirstLineException m_Exception;
663
  };
664
665
  // -------- Class HttpResponseFirstLine -----------------
666
667
  /// @class HttpResponseFirstLine
668
  /// Represents an HTTP response header first line. The first line includes 2 parameters: status code (e.g 200 OK,
669
  /// 404 Not Found, etc.), and HTTP version (e.g HTTP/1.1). These 2 parameters are included in this class, and the
670
  /// user can retrieve or set them. This class cannot be instantiated by users, it's created inside HttpResponseLayer
671
  /// and user can get a pointer to an instance of it. The "get" methods of this class will retrieve the actual data
672
  /// of the HTTP response and the "set" methods will change the packet data. Since HTTP is a textual protocol, most
673
  /// fields aren't of fixed size and this also applies to the first line parameters. So most "set" methods of this
674
  /// class need in most cases to shorten or extend the data in HttpResponseLayer. These methods will return a false
675
  /// value if this action failed
676
  class HttpResponseFirstLine
677
  {
678
    friend class HttpResponseLayer;
679
680
  public:
681
    /// @return The status code as HttpResponseStatusCode enum
682
    HttpResponseStatusCode getStatusCode() const
683
0
    {
684
0
      return m_StatusCode;
685
0
    }
686
687
    /// @return The status code number as integer (e.g 200, 404, etc.)
688
    int getStatusCodeAsInt() const;
689
690
    /// @return The status code message (e.g "OK", "Not Found", etc.)
691
    std::string getStatusCodeString() const;
692
693
    /// Set the status code
694
    /// @param[in] newStatusCode The new status code to set
695
    /// @param[in] statusCodeString An optional parameter: set a non-default status code message (e.g "Bla Bla"
696
    /// instead of "Not Found"). If this parameter isn't supplied or supplied as empty string (""), the default
697
    /// message for the status code will be set
698
    /// @return True if setting the status code was completed successfully, false otherwise
699
    /// @deprecated Use the other overload instead.
700
    PCPP_DEPRECATED("Use the other overload instead")
701
    bool setStatusCode(const HttpResponseStatusCode& newStatusCode, const std::string& statusCodeString);
702
703
    /// Set the status code
704
    /// @param[in] newStatusCode The new status code to set
705
    /// @return True if setting the status code was completed successfully, false otherwise
706
    bool setStatusCode(const HttpResponseStatusCode& newStatusCode);
707
708
    /// @return The HTTP version
709
    HttpVersion getVersion() const
710
0
    {
711
0
      return m_Version;
712
0
    }
713
714
    /// Set the HTTP version. This method doesn't return a value since all supported HTTP versions are of the same
715
    /// size (HTTP/0.9, HTTP/1.0, HTTP/1.1)
716
    /// @param[in] newVersion The HTTP version to set
717
    void setVersion(HttpVersion newVersion);
718
719
    /// A static method for parsing the HTTP status code out of raw data
720
    /// @param[in] data The raw data
721
    /// @param[in] dataLen The raw data length
722
    /// @return The parsed HTTP status code as enum
723
    static HttpResponseStatusCode parseStatusCode(const char* data, size_t dataLen);
724
725
    /// A static method for parsing the HTTP version out of raw first line data (e.g "HTTP/x.y")
726
    /// @param[in] data The raw data
727
    /// @param[in] dataLen The raw data length
728
    /// @return The parsed HTTP status code as enum
729
    static HttpVersion parseVersion(const char* data, size_t dataLen);
730
731
    /// @return The size in bytes of the HTTP first line
732
    int getSize() const
733
5.13k
    {
734
5.13k
      return m_FirstLineEndOffset;
735
5.13k
    }
736
737
    /// As explained in HttpResponseLayer, an HTTP header can spread over more than 1 packet, so when looking at a
738
    /// single packet the header can be partial. Same goes for the first line - it can spread over more than 1
739
    /// packet. This method returns an indication whether the first line is partial
740
    /// @return False if the first line is partial, true if it's complete
741
    bool isComplete() const
742
0
    {
743
0
      return m_IsComplete;
744
0
    }
745
746
    /// @class HttpResponseFirstLineException
747
    /// This exception can be thrown while constructing HttpResponseFirstLine (the constructor is private, so the
748
    /// construction happens only in HttpResponseLayer). This kind of exception will be thrown if trying to
749
    /// construct with a HTTP status code that is not in HttpResponseStatusCode or with undefined HTTP version
750
    /// ::HttpVersionUnknown
751
    class HttpResponseFirstLineException : public std::exception
752
    {
753
    public:
754
      ~HttpResponseFirstLineException() noexcept
755
3.70k
      {}
756
      void setMessage(const std::string& message)
757
0
      {
758
0
        m_Message = message;
759
0
      }
760
      virtual const char* what() const noexcept
761
0
      {
762
0
        return m_Message.c_str();
763
0
      }
764
765
    private:
766
      std::string m_Message;
767
    };
768
769
  private:
770
    HttpResponseFirstLine(HttpResponseLayer* httpResponse);
771
    HttpResponseFirstLine(HttpResponseLayer* httpResponse, HttpVersion version,
772
                          const HttpResponseStatusCode& statusCode);
773
774
    HttpResponseLayer* m_HttpResponse;
775
    HttpVersion m_Version;
776
    HttpResponseStatusCode m_StatusCode;
777
    int m_FirstLineEndOffset;
778
    bool m_IsComplete;
779
    HttpResponseFirstLineException m_Exception;
780
  };
781
782
}  // namespace pcpp