Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement HttpResponseStatusCode toString & toInt #1180

Merged
merged 28 commits into from
Aug 26, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1a80c82
implement HttpResponseStatusCode toString & toInt
tigercosmos Jul 26, 2023
e98a719
simplified the code in HttpResponseParseStatusCodeTest
tigercosmos Aug 11, 2023
8a93743
updated status code according to the latest spec
tigercosmos Aug 12, 2023
45d02a8
put previously supported code back
tigercosmos Aug 15, 2023
2afa3e8
HttpResponseStatusCode backward compatibility
tigercosmos Aug 15, 2023
9645cd5
improve http test
tigercosmos Aug 15, 2023
03d73e7
format
tigercosmos Aug 15, 2023
03bbf4d
fix test
tigercosmos Aug 15, 2023
f6df30d
HttpResponseStatusCode initial value
tigercosmos Aug 15, 2023
3eb74d8
update doc
tigercosmos Aug 16, 2023
8002ca2
Merge branch 'dev' into 20230812HttpStatusCode
tigercosmos Aug 16, 2023
2e33f38
disable cppcheck for a line
tigercosmos Aug 16, 2023
a257f45
Merge branch '20230812HttpStatusCode' of https://github.com/tigercosm…
tigercosmos Aug 16, 2023
12a9527
move HttpResponseStatusCodeHash to cpp
tigercosmos Aug 20, 2023
cfd3461
fix comment
tigercosmos Aug 20, 2023
8ff4b89
refactor a little bit
tigercosmos Aug 20, 2023
7d036f7
more efficient way to construct HttpResponseStatusCode from int
tigercosmos Aug 20, 2023
e259e35
Rename `m_value` to `m_Value`
seladb Aug 24, 2023
01f8490
Rename `m_value` to `m_Value`
seladb Aug 24, 2023
5fe8ebe
prevent using stoi
tigercosmos Aug 24, 2023
2b57ca8
fix logic
tigercosmos Aug 24, 2023
490c0fd
simplify HttpResponseStatusCodeHash
tigercosmos Aug 24, 2023
363a695
Merge branch '20230812HttpStatusCode' of github.com:tigercosmos/PcapP…
tigercosmos Aug 17, 2023
b8f1327
suppress containerOutOfBounds
tigercosmos Aug 24, 2023
6115b3b
fix logic
tigercosmos Aug 25, 2023
5760ce7
fix wrong logic
tigercosmos Aug 25, 2023
4703115
fix
tigercosmos Aug 25, 2023
e0eb088
Merge branch 'dev' into 20230812HttpStatusCode
seladb Aug 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
253 changes: 141 additions & 112 deletions Packet++/header/HttpLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,201 +207,230 @@ namespace pcpp
HttpRequestFirstLine* m_FirstLine;
};





// -------- Class HttpResponseLayer -----------------

class HttpResponseFirstLine;

// -------- Class HttpResponseStatusCode -----------------

/**
* @class HttpResponseLayer
* Represents an HTTP response header and inherits all basic functionality of HttpMessage and TextBasedProtocolMessage.
* The functionality that is added for this class is the HTTP first line concept. An HTTP response has the following first line:
* <i>200 OK HTTP/1.1</i>
* Since it's not an "ordinary" HTTP field, it requires a special treatment and gets a class of it's own: HttpResponseFirstLine.
* Unlike most L2-4 protocols, an HTTP response header can spread over more than 1 packet. PcapPlusPlus currently doesn't support a header
* 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
* 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
* 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
* HttpMessage#isHeaderComplete()
* Class for the enum of HTTP response status codes
*/
class HttpResponseLayer : public HttpMessage
class HttpResponseStatusCode
tigercosmos marked this conversation as resolved.
Show resolved Hide resolved
{
friend class HttpResponseFirstLine;
public:
/**
* Enum for HTTP response status codes
*/
enum HttpResponseStatusCode
enum Value: int
seladb marked this conversation as resolved.
Show resolved Hide resolved
{
/** 100 Continue*/
Http100Continue,
Http100Continue = 100,
seladb marked this conversation as resolved.
Show resolved Hide resolved
/** 101 Switching Protocols*/
Http101SwitchingProtocols,
Http101SwitchingProtocols = 101,
/** 102 Processing */
Http102Processing,
Http102Processing = 102,
/** 200 OK */
Http200OK,
Http200OK= 200,
/** 201 Created */
Http201Created,
Http201Created = 201,
/** 202 Accepted */
Http202Accepted,
Http202Accepted = 202,
/** 203 Non-Authoritative Information */
Http203NonAuthoritativeInformation,
Http203NonAuthoritativeInformation = 203,
/** 204 No Content*/
Http204NoContent,
Http204NoContent = 204,
/** 205 Reset Content*/
Http205ResetContent,
Http205ResetContent = 205,
/** 206 Partial Content */
Http206PartialContent,
Http206PartialContent = 206,
/** 207 Multi-Status */
Http207MultiStatus,
Http207MultiStatus = 207,
/** 208 Already Reported */
Http208AlreadyReported,
Http208AlreadyReported = 208,
/** 226 IM Used */
Http226IMUsed,
Http226IMUsed = 226,
/** 300 Multiple Choices */
Http300MultipleChoices,
Http300MultipleChoices = 300,
/** 301 Moved Permanently */
Http301MovedPermanently,
Http301MovedPermanently = 301,
/** 302 (various messages) */
Http302,
Http302 = 302,
/** 303 See Other */
Http303SeeOther,
Http303SeeOther = 303,
/** 304 Not Modified */
Http304NotModified,
Http304NotModified = 304,
/** 305 Use Proxy */
Http305UseProxy,
Http305UseProxy = 305,
/** 306 Switch Proxy */
Http306SwitchProxy,
Http306SwitchProxy = 306,
/** 307 Temporary Redirect */
Http307TemporaryRedirect,
Http307TemporaryRedirect = 307,
/** 308 Permanent Redirect, */
Http308PermanentRedirect,
Http308PermanentRedirect = 308,
/** 400 Bad Request */
Http400BadRequest,
Http400BadRequest = 400,
/** 401 Unauthorized */
Http401Unauthorized,
Http401Unauthorized = 401,
/** 402 Payment Required */
Http402PaymentRequired,
Http402PaymentRequired = 402,
/** 403 Forbidden */
Http403Forbidden,
Http403Forbidden = 403,
/** 404 Not Found */
Http404NotFound,
Http404NotFound = 404,
/** 405 Method Not Allowed */
Http405MethodNotAllowed,
Http405MethodNotAllowed = 405,
/** 406 Not Acceptable */
Http406NotAcceptable,
Http406NotAcceptable = 406,
/** 407 Proxy Authentication Required */
Http407ProxyAuthenticationRequired,
Http407ProxyAuthenticationRequired = 407,
/** 408 Request Timeout */
Http408RequestTimeout,
Http408RequestTimeout = 408,
/** 409 Conflict */
Http409Conflict,
Http409Conflict = 409,
/** 410 Gone */
Http410Gone,
Http410Gone = 410,
/** 411 Length Required */
Http411LengthRequired,
Http411LengthRequired = 411,
/** 412 Precondition Failed */
Http412PreconditionFailed,
Http412PreconditionFailed = 412,
/** 413 RequestEntity Too Large */
Http413RequestEntityTooLarge,
Http413RequestEntityTooLarge = 413,
/** 414 Request-URI Too Long */
Http414RequestURITooLong,
Http414RequestURITooLong = 414,
/** 415 Unsupported Media Type */
Http415UnsupportedMediaType,
Http415UnsupportedMediaType = 415,
/** 416 Requested Range Not Satisfiable */
Http416RequestedRangeNotSatisfiable,
Http416RequestedRangeNotSatisfiable = 416,
/** 417 Expectation Failed */
Http417ExpectationFailed,
Http417ExpectationFailed = 417,
/** 418 I'm a teapot */
Http418ImATeapot,
Http418ImATeapot = 418,
/** 419 Authentication Timeout */
Http419AuthenticationTimeout,
Http419AuthenticationTimeout = 419,
/** 420 (various messages) */
Http420,
Http420 = 420,
/** 422 Unprocessable Entity */
Http422UnprocessableEntity,
Http422UnprocessableEntity = 422,
/** 423 Locked */
Http423Locked,
Http423Locked = 423,
/** 424 Failed Dependency */
Http424FailedDependency,
Http424FailedDependency = 424,
/** 426 Upgrade Required */
Http426UpgradeRequired,
Http426UpgradeRequired = 426,
/** 428 Precondition Required */
Http428PreconditionRequired,
Http428PreconditionRequired = 428,
/** 429 Too Many Requests */
Http429TooManyRequests,
Http429TooManyRequests = 429,
/** 431 Request Header Fields Too Large */
Http431RequestHeaderFieldsTooLarge,
Http431RequestHeaderFieldsTooLarge = 431,
/** 440 Login Timeout */
Http440LoginTimeout,
Http440LoginTimeout = 440,
/** 444 No Response */
Http444NoResponse,
Http444NoResponse = 444,
/** 449 Retry With */
Http449RetryWith,
Http449RetryWith = 449,
/** 450 Blocked by Windows Parental Controls */
Http450BlockedByWindowsParentalControls,
Http450BlockedByWindowsParentalControls = 450,
/** 451 (various messages) */
Http451,
Http451 = 451,
/** 494 Request Header Too Large */
Http494RequestHeaderTooLarge,
Http494RequestHeaderTooLarge = 494,
/** 495 Cert Error */
Http495CertError,
Http495CertError = 495,
/** 496 No Cert */
Http496NoCert,
Http496NoCert = 496,
/** 497 HTTP to HTTPS */
Http497HTTPtoHTTPS,
Http497HTTPtoHTTPS = 497,
/** 498 Token expired/invalid */
Http498TokenExpiredInvalid,
Http498TokenExpiredInvalid = 498,
/** 499 (various messages) */
Http499,
Http499 = 499,
/** 500 Internal Server Error */
Http500InternalServerError,
Http500InternalServerError = 500,
/** 501 Not Implemented */
Http501NotImplemented,
Http501NotImplemented = 501,
/** 502 Bad Gateway */
Http502BadGateway,
Http502BadGateway = 502,
/** 503 Service Unavailable */
Http503ServiceUnavailable,
Http503ServiceUnavailable = 503,
/** 504 Gateway Timeout */
Http504GatewayTimeout,
Http504GatewayTimeout = 504,
/** 505 HTTP Version Not Supported */
Http505HTTPVersionNotSupported,
Http505HTTPVersionNotSupported = 505,
/** 506 Variant Also Negotiates */
Http506VariantAlsoNegotiates,
Http506VariantAlsoNegotiates = 506,
/** 507 Insufficient Storage */
Http507InsufficientStorage,
Http507InsufficientStorage = 507,
/** 508 Loop Detected */
Http508LoopDetected,
Http508LoopDetected = 508,
/** 509 Bandwidth Limit Exceeded */
Http509BandwidthLimitExceeded,
Http509BandwidthLimitExceeded = 509,
/** 510 Not Extended */
Http510NotExtended,
Http510NotExtended = 510,
/** 511 Network Authentication Required */
Http511NetworkAuthenticationRequired,
Http511NetworkAuthenticationRequired = 511,
/** 520 Origin Error */
Http520OriginError,
Http520OriginError = 520,
/** 521 Web server is down */
Http521WebServerIsDown,
Http521WebServerIsDown = 521,
/** 522 Connection timed out */
Http522ConnectionTimedOut,
Http522ConnectionTimedOut = 522,
/** 523 Proxy Declined Request */
Http523ProxyDeclinedRequest,
Http523ProxyDeclinedRequest = 523,
/** 524 A timeout occurred */
Http524aTimeoutOccurred,
Http524aTimeoutOccurred = 524,
/** 598 Network read timeout error */
Http598NetworkReadTimeoutError,
Http598NetworkReadTimeoutError = 598,
/** 599 Network connect timeout error */
Http599NetworkConnectTimeoutError,
Http599NetworkConnectTimeoutError = 599,
/** Unknown status code */
HttpStatusCodeUnknown
HttpStatusCodeUnknown = 999999
};

HttpResponseStatusCode() = default;
constexpr HttpResponseStatusCode(Value statusCode) : m_value(statusCode) { }
seladb marked this conversation as resolved.
Show resolved Hide resolved
seladb marked this conversation as resolved.
Show resolved Hide resolved

constexpr operator Value() const { return m_value; }
explicit operator bool() const = delete;
tigercosmos marked this conversation as resolved.
Show resolved Hide resolved

struct HttpResponseStatusCodeHash {
tigercosmos marked this conversation as resolved.
Show resolved Hide resolved
tigercosmos marked this conversation as resolved.
Show resolved Hide resolved
size_t operator()(const HttpResponseStatusCode& status) const {
return std::hash<int>()(static_cast<int>(status));
}
};

std::string toString() const {
return std::to_string(m_value);
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we also want to expose the code message and not only the value.
Currently this method will return the code as string, for example: "200" but there's no method to return "OK".
If we expose a method to return the message, we can also support customer messages. For example, you can do:

HttpResponseStatusCode statusCode1(HttpResponseStatusCode::Http200OK);
HttpResponseStatusCode statusCode2(HttpResponseStatusCode::Http200OK, "Custom message");

std::cout << statusCode1.getMessage();
// prints "OK"
std::cout << statusCode2.getMessage();
// prints "Custom message"

But maybe we can leave it to a separate PR?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea. let's add this getMessage function in this PR

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we should add it to this PR because it'll create more changes and require more tests. Maybe we can have a follow-up PR right after we merge this one?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, okay for me


int toInt() const {
return m_value;
}

constexpr bool operator==(const HttpResponseStatusCode &other) const { return m_value == other.m_value; }
constexpr bool operator!=(const HttpResponseStatusCode &other) const { return m_value != other.m_value; }

constexpr bool operator==(const Value &otherValue) const { return m_value == otherValue; }
constexpr bool operator!=(const Value &otherValue) const { return m_value != otherValue; }
tigercosmos marked this conversation as resolved.
Show resolved Hide resolved
private:
Value m_value;
};

// -------- Class HttpResponseLayer -----------------

class HttpResponseFirstLine;


/**
* @class HttpResponseLayer
* Represents an HTTP response header and inherits all basic functionality of HttpMessage and TextBasedProtocolMessage.
* The functionality that is added for this class is the HTTP first line concept. An HTTP response has the following first line:
* <i>200 OK HTTP/1.1</i>
* Since it's not an "ordinary" HTTP field, it requires a special treatment and gets a class of it's own: HttpResponseFirstLine.
* Unlike most L2-4 protocols, an HTTP response header can spread over more than 1 packet. PcapPlusPlus currently doesn't support a header
* 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
* 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
* 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
* HttpMessage#isHeaderComplete()
*/
class HttpResponseLayer : public HttpMessage
{
friend class HttpResponseFirstLine;
public:
/** A constructor that creates the layer from an existing packet raw data
* @param[in] data A pointer to the raw data
* @param[in] dataLen Size of the data in bytes
Expand All @@ -419,7 +448,7 @@ namespace pcpp
* 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
* default status code string
*/
HttpResponseLayer(HttpVersion version, HttpResponseLayer::HttpResponseStatusCode statusCode, std::string statusCodeString = "");
HttpResponseLayer(HttpVersion version, HttpResponseStatusCode statusCode, std::string statusCodeString = "");

virtual ~HttpResponseLayer();

Expand Down Expand Up @@ -606,9 +635,9 @@ namespace pcpp
friend class HttpResponseLayer;
public:
/**
* @return The status code as HttpResponseLayer::HttpResponseStatusCode enum
* @return The status code as HttpResponseStatusCode enum
*/
HttpResponseLayer::HttpResponseStatusCode getStatusCode() const { return m_StatusCode; }
HttpResponseStatusCode getStatusCode() const { return m_StatusCode; }

/**
* @return The status code number as integer (e.g 200, 404, etc.)
Expand All @@ -627,7 +656,7 @@ namespace pcpp
* this parameter isn't supplied or supplied as empty string (""), the default message for the status code will be set
* @return True if setting the status code was completed successfully, false otherwise
*/
bool setStatusCode(HttpResponseLayer::HttpResponseStatusCode newStatusCode, std::string statusCodeString = "");
bool setStatusCode(HttpResponseStatusCode newStatusCode, std::string statusCodeString = "");

/**
* @return The HTTP version
Expand All @@ -647,7 +676,7 @@ namespace pcpp
* @param[in] dataLen The raw data length
* @return The parsed HTTP status code as enum
*/
static HttpResponseLayer::HttpResponseStatusCode parseStatusCode(const char* data, size_t dataLen);
static HttpResponseStatusCode parseStatusCode(const char* data, size_t dataLen);

/**
* A static method for parsing the HTTP version out of raw first line data (e.g "HTTP/x.y")
Expand Down Expand Up @@ -691,11 +720,11 @@ namespace pcpp

private:
HttpResponseFirstLine(HttpResponseLayer* httpResponse);
HttpResponseFirstLine(HttpResponseLayer* httpResponse, HttpVersion version, HttpResponseLayer::HttpResponseStatusCode statusCode, std::string statusCodeString = "");
HttpResponseFirstLine(HttpResponseLayer* httpResponse, HttpVersion version, HttpResponseStatusCode statusCode, std::string statusCodeString = "");

HttpResponseLayer* m_HttpResponse;
HttpVersion m_Version;
HttpResponseLayer::HttpResponseStatusCode m_StatusCode;
HttpResponseStatusCode m_StatusCode;
int m_FirstLineEndOffset;
bool m_IsComplete;
HttpResponseFirstLineException m_Exception;
Expand Down
Loading