Coverage Report

Created: 2024-02-25 06:29

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