Skip to content

Commit

Permalink
Merge branch 'seladb:master' into dev_port_C11_HttpAnalyzer
Browse files Browse the repository at this point in the history
  • Loading branch information
jpcofr authored Sep 19, 2023
2 parents 4c76009 + b6d1801 commit 7e575cc
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 49 deletions.
72 changes: 56 additions & 16 deletions Packet++/header/HttpLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@
#include <string>
#include <exception>

#ifndef PCPP_DEPRECATED
#if defined(__GNUC__) || defined(__clang__)
#define PCPP_DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define PCPP_DEPRECATED __declspec(deprecated)
#else
#pragma message("WARNING: DEPRECATED feature is not implemented for this compiler")
#define PCPP_DEPRECATED
#endif
#endif

/// @file

/**
Expand Down Expand Up @@ -59,6 +70,12 @@ namespace pcpp
#define PCPP_HTTP_SERVER_FIELD "Server"


// -------- classes to be defined later -----------------


class HttpRequestFirstLine;
class HttpResponseFirstLine;


// -------- Class HttpMessage -----------------

Expand Down Expand Up @@ -101,12 +118,6 @@ namespace pcpp
};




class HttpRequestFirstLine;



// -------- Class HttpRequestLayer -----------------

/**
Expand Down Expand Up @@ -418,16 +429,26 @@ namespace pcpp
// cppcheck-suppress noExplicitConstructor
/**
* @brief Construct HttpResponseStatusCode from Value enum
* @param[in] statusCode the status code enum
*/
HttpResponseStatusCode(Value statusCode) : m_Value(statusCode) { }

/**
* @brief Construct HttpResponseStatusCode from the code number and the customized message
* @param[in] statusCodeNumber the status code in number, e.g. 200, 404
* @param[in] statusMessage the status message, optional, leave empty to use a default message
*/
constexpr HttpResponseStatusCode(Value statusCode) : m_Value(statusCode) { }
explicit HttpResponseStatusCode(const int &statusCodeNumber, const std::string& statusMessage = "");

/**
* @brief Construct HttpResponseStatusCode from int
* @brief Construct HttpResponseStatusCode from Value enum and the customized message
* @param[in] statusCode the status code enum
* @param[in] statusMessage the customized status message, optional
*/
explicit HttpResponseStatusCode(const int &statusCodeNumber);
explicit HttpResponseStatusCode(const Value& statusCode, const std::string& statusMessage);

// Allow switch and comparisons.
constexpr operator Value() const { return m_Value; }
operator Value() const { return m_Value; }
// Prevent usage: if(httpResponseStatusCode)
explicit operator bool() const = delete;

Expand All @@ -447,6 +468,10 @@ namespace pcpp
return static_cast<int>(m_Value);
}

/**
* @brief get status code message, e.g. "OK", "Not Found"
*/
std::string getMessage() const;
/**
* @return If this HttpResponseStatusCode a valid code
* @note Any unknown or error code has an extreme large enum value
Expand All @@ -458,13 +483,11 @@ namespace pcpp

private:
Value m_Value = HttpStatusCodeUnknown;
std::string m_CustomizedMessage;
};

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

class HttpResponseFirstLine;


/**
* @class HttpResponseLayer
* Represents an HTTP response header and inherits all basic functionality of HttpMessage and TextBasedProtocolMessage.
Expand Down Expand Up @@ -500,8 +523,17 @@ namespace pcpp
* @param[in] statusCodeString Most status codes have their default string, e.g 200 is usually "OK", 404 is usually "Not Found", etc.
* 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
* @deprecated Use other constructors instead.
*/
PCPP_DEPRECATED explicit HttpResponseLayer(HttpVersion version, const HttpResponseStatusCode& statusCode, const std::string& statusCodeString);

/**
* A constructor that allocates a new HTTP response header with only the first line filled. Object will be created without further fields.
* The user can then add fields using addField() methods
* @param[in] version HTTP version to be used
* @param[in] statusCode Status code to be used
*/
HttpResponseLayer(HttpVersion version, HttpResponseStatusCode statusCode, std::string statusCodeString = "");
explicit HttpResponseLayer(HttpVersion version, const HttpResponseStatusCode& statusCode);

virtual ~HttpResponseLayer();

Expand Down Expand Up @@ -708,8 +740,16 @@ namespace pcpp
* @param[in] statusCodeString An optional parameter: set a non-default status code message (e.g "Bla Bla" instead of "Not Found"). If
* 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
* @deprecated Use the other overload instead.
*/
PCPP_DEPRECATED bool setStatusCode(const HttpResponseStatusCode& newStatusCode, const std::string& statusCodeString);

/**
* Set the status code
* @param[in] newStatusCode The new status code to set
* @return True if setting the status code was completed successfully, false otherwise
*/
bool setStatusCode(HttpResponseStatusCode newStatusCode, std::string statusCodeString = "");
bool setStatusCode(const HttpResponseStatusCode& newStatusCode);

/**
* @return The HTTP version
Expand Down Expand Up @@ -773,7 +813,7 @@ namespace pcpp

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

HttpResponseLayer* m_HttpResponse;
HttpVersion m_Version;
Expand Down
97 changes: 75 additions & 22 deletions Packet++/src/HttpLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,8 +534,13 @@ static const std::unordered_map<int, HttpResponseStatusCode> intStatusCodeMap =
{599, HttpResponseStatusCode::Http599NetworkConnectTimeoutError},
};

HttpResponseStatusCode::HttpResponseStatusCode(const int &statusCodeNumber)
HttpResponseStatusCode::HttpResponseStatusCode(const int &statusCodeNumber, const std::string& statusMessage)
{
if(statusMessage != "")
{
m_CustomizedMessage = statusMessage;
}

if(intStatusCodeMap.find(statusCodeNumber) != intStatusCodeMap.end())
{
m_Value = intStatusCodeMap.at(statusCodeNumber);
Expand Down Expand Up @@ -668,6 +673,23 @@ static const std::unordered_map<HttpResponseStatusCode, std::string, HttpRespons
{HttpResponseStatusCode::HttpStatusCodeUnknown, "Status Code Unknown"},
};

HttpResponseStatusCode::HttpResponseStatusCode(const Value& statusCode, const std::string& statusMessage) : m_Value(statusCode)
{
if(statusMessage != "")
{
m_CustomizedMessage = statusMessage;
}
}

std::string HttpResponseStatusCode::getMessage() const
{
if(m_CustomizedMessage != "")
{
return m_CustomizedMessage;
}
return statusCodeExplanationStringMap.at(m_Value);
}

HttpResponseLayer::HttpResponseLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : HttpMessage(data, dataLen, prevLayer, packet)
{
m_Protocol = HTTPResponse;
Expand All @@ -676,10 +698,17 @@ HttpResponseLayer::HttpResponseLayer(uint8_t* data, size_t dataLen, Layer* prevL
parseFields();
}

HttpResponseLayer::HttpResponseLayer(HttpVersion version, HttpResponseStatusCode statusCode, std::string statusCodeString)
HttpResponseLayer::HttpResponseLayer(HttpVersion version, const HttpResponseStatusCode& statusCode, const std::string& statusCodeString)
{
m_Protocol = HTTPResponse;
m_FirstLine = new HttpResponseFirstLine(this, version, HttpResponseStatusCode(statusCode, statusCodeString));
m_FieldsOffset = m_FirstLine->getSize();
}

HttpResponseLayer::HttpResponseLayer(HttpVersion version, const HttpResponseStatusCode& statusCode)
{
m_Protocol = HTTPResponse;
m_FirstLine = new HttpResponseFirstLine(this, version, statusCode, std::move(statusCodeString));
m_FirstLine = new HttpResponseFirstLine(this, version, statusCode);
m_FieldsOffset = m_FirstLine->getSize();
}

Expand Down Expand Up @@ -772,22 +801,21 @@ int HttpResponseFirstLine::getStatusCodeAsInt() const

std::string HttpResponseFirstLine::getStatusCodeString() const
{
std::string result;
const int statusStringOffset = 13;
if (!m_StatusCode.isUnsupportedCode())
{
int statusStringEndOffset = m_FirstLineEndOffset - 2;
if ((*(m_HttpResponse->m_Data + statusStringEndOffset)) != '\r')
statusStringEndOffset++;
result.assign((char*)(m_HttpResponse->m_Data + statusStringOffset), statusStringEndOffset-statusStringOffset);
return m_StatusCode.getMessage();
}

//else first line is illegal, return empty string
return "";
}

return result;
bool HttpResponseFirstLine::setStatusCode(const HttpResponseStatusCode& newStatusCode, const std::string& statusCodeString)
{
return setStatusCode(HttpResponseStatusCode(newStatusCode, statusCodeString));
}

bool HttpResponseFirstLine::setStatusCode(HttpResponseStatusCode newStatusCode, std::string statusCodeString)
bool HttpResponseFirstLine::setStatusCode(const HttpResponseStatusCode& newStatusCode)
{
if (newStatusCode.isUnsupportedCode())
{
Expand All @@ -798,9 +826,9 @@ bool HttpResponseFirstLine::setStatusCode(HttpResponseStatusCode newStatusCode,
//extend or shorten layer

size_t statusStringOffset = 13;
if (statusCodeString == "")
statusCodeString = statusCodeExplanationStringMap.at(newStatusCode);
int lengthDifference = statusCodeString.length() - getStatusCodeString().length();
auto newStatusCodeMessage = newStatusCode.getMessage();

int lengthDifference = newStatusCodeMessage.length() - getStatusCodeString().length();
if (lengthDifference > 0)
{
if (!m_HttpResponse->extendLayer(statusStringOffset, lengthDifference))
Expand All @@ -823,7 +851,7 @@ bool HttpResponseFirstLine::setStatusCode(HttpResponseStatusCode newStatusCode,
m_HttpResponse->shiftFieldsOffset(m_HttpResponse->getFirstField(), lengthDifference);

// copy status string
memcpy(m_HttpResponse->m_Data+statusStringOffset, statusCodeString.c_str(), statusCodeString.length());
memcpy(m_HttpResponse->m_Data+statusStringOffset, newStatusCodeMessage.c_str(), newStatusCodeMessage.length());

// change status code
memcpy(m_HttpResponse->m_Data+9, newStatusCode.toString().c_str(), 3);
Expand Down Expand Up @@ -855,14 +883,42 @@ HttpResponseStatusCode HttpResponseFirstLine::parseStatusCode(const char* data,
return HttpResponseStatusCode::HttpStatusCodeUnknown;
}

std::string codeString = std::string(data + 9, 3);
const std::string codeString = std::string(data + 9, 3);

if(codeString.empty() || (std::find_if(codeString.begin(), codeString.end(), [](unsigned char c){ return !std::isdigit(c); }) != codeString.end()))
{
return HttpResponseStatusCode::HttpStatusCodeUnknown;
}

return HttpResponseStatusCode(std::stoi(codeString));
constexpr size_t messageOffset = 13; // expect "HTTP/x.y XXX YYY", YYY starts from 13
size_t offset = messageOffset;
bool isMessageFound = false;
while(offset < dataLen)
{
if(data[offset] == '\n')
{
isMessageFound = true;
break;
}
offset++;
}

if(!isMessageFound)
{
return HttpResponseStatusCode::HttpStatusCodeUnknown;
}

std::string messageString(data + messageOffset, offset - messageOffset);
if(!messageString.empty() && messageString.back() == '\r')
{
messageString.pop_back();
}
if(messageString.empty())
{
return HttpResponseStatusCode::HttpStatusCodeUnknown;
}

return HttpResponseStatusCode(std::stoi(codeString), messageString);
}

HttpResponseFirstLine::HttpResponseFirstLine(HttpResponseLayer* httpResponse) : m_HttpResponse(httpResponse)
Expand Down Expand Up @@ -899,7 +955,7 @@ HttpResponseFirstLine::HttpResponseFirstLine(HttpResponseLayer* httpResponse) :
}


HttpResponseFirstLine::HttpResponseFirstLine(HttpResponseLayer* httpResponse, HttpVersion version, HttpResponseStatusCode statusCode, std::string statusCodeString)
HttpResponseFirstLine::HttpResponseFirstLine(HttpResponseLayer* httpResponse, HttpVersion version, const HttpResponseStatusCode& statusCode)
{
if (statusCode.isUnsupportedCode())
{
Expand All @@ -918,10 +974,7 @@ HttpResponseFirstLine::HttpResponseFirstLine(HttpResponseLayer* httpResponse, H
m_StatusCode = statusCode;
m_Version = version;

if(statusCodeString == "") {
statusCodeString = statusCodeExplanationStringMap.at(m_StatusCode);
}
std::string firstLine = "HTTP/" + VersionEnumToString[m_Version] + " " + m_StatusCode.toString() + " " + statusCodeString + "\r\n";
std::string firstLine = "HTTP/" + VersionEnumToString[m_Version] + " " + m_StatusCode.toString() + " " + m_StatusCode.getMessage() + "\r\n";

m_FirstLineEndOffset = firstLine.length();

Expand Down
Loading

0 comments on commit 7e575cc

Please sign in to comment.