Coverage Report

Created: 2026-11-12 06:50

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