Coverage Report

Created: 2023-01-17 06:15

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