Skip to content

Commit

Permalink
support getMessage
Browse files Browse the repository at this point in the history
  • Loading branch information
tigercosmos committed Sep 6, 2023
1 parent 666e292 commit cc2608c
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 35 deletions.
34 changes: 22 additions & 12 deletions Packet++/header/HttpLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,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 +107,6 @@ namespace pcpp
};




class HttpRequestFirstLine;



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

/**
Expand Down Expand Up @@ -419,12 +419,17 @@ namespace pcpp
/**
* @brief Construct HttpResponseStatusCode from Value enum
*/
constexpr HttpResponseStatusCode(Value statusCode) : m_Value(statusCode) { }
HttpResponseStatusCode(Value statusCode) : m_Value(statusCode) { }

/**
* @brief Construct HttpResponseStatusCode from int
* @brief Construct HttpResponseStatusCode from the code number and the customized message
*/
explicit HttpResponseStatusCode(const int &statusCodeNumber);
explicit HttpResponseStatusCode(const int &statusCodeNumber, const std::string statusMessage = "");

/**
* @brief Construct HttpResponseStatusCode from Value enum and the customized message
*/
explicit HttpResponseStatusCode(const Value& statusCode, const std::string& statusMessage);

// Allow switch and comparisons.
constexpr operator Value() const { return m_Value; }
Expand All @@ -447,6 +452,11 @@ 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 @@ -457,14 +467,14 @@ namespace pcpp
}

private:
friend class HttpResponseFirstLine;

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
74 changes: 53 additions & 21 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,24 @@ 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 = statusCodeExplanationStringMap.at(statusCode);
} else {
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 Down Expand Up @@ -772,19 +795,13 @@ 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 result;
return "";
}

bool HttpResponseFirstLine::setStatusCode(HttpResponseStatusCode newStatusCode, std::string statusCodeString)
Expand All @@ -797,10 +814,11 @@ bool HttpResponseFirstLine::setStatusCode(HttpResponseStatusCode newStatusCode,

//extend or shorten layer

HttpResponseStatusCode newStatusCodeWithMessage(newStatusCode, statusCodeString);

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

int lengthDifference = newStatusCodeWithMessage.getMessage().length() - getStatusCodeString().length();
if (lengthDifference > 0)
{
if (!m_HttpResponse->extendLayer(statusStringOffset, lengthDifference))
Expand All @@ -823,12 +841,12 @@ 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, newStatusCodeWithMessage.getMessage().c_str(), newStatusCodeWithMessage.getMessage().length());

// change status code
memcpy(m_HttpResponse->m_Data+9, newStatusCode.toString().c_str(), 3);

m_StatusCode = newStatusCode;
m_StatusCode = newStatusCodeWithMessage;

m_FirstLineEndOffset += lengthDifference;

Expand All @@ -855,14 +873,31 @@ 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++;
}
std::string messageString = isMessageFound ? std::string(data + messageOffset, offset - messageOffset) : "";
if(messageString.back() == '\r')
{
messageString.pop_back();
}
return HttpResponseStatusCode(std::stoi(codeString), messageString);
}

HttpResponseFirstLine::HttpResponseFirstLine(HttpResponseLayer* httpResponse) : m_HttpResponse(httpResponse)
Expand Down Expand Up @@ -915,13 +950,10 @@ HttpResponseFirstLine::HttpResponseFirstLine(HttpResponseLayer* httpResponse, H

m_HttpResponse = httpResponse;

m_StatusCode = statusCode;
m_StatusCode = HttpResponseStatusCode(statusCode, statusCodeString);
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
19 changes: 17 additions & 2 deletions Tests/Packet++Test/Tests/HttpTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include "HttpLayer.h"
#include "PayloadLayer.h"
#include "SystemUtils.h"

#include <iostream>
PTF_TEST_CASE(HttpRequestParseMethodTest)
{
PTF_ASSERT_EQUAL(pcpp::HttpRequestFirstLine::parseMethod(nullptr, 0), pcpp::HttpRequestLayer::HttpMethod::HttpMethodUnknown, enum);
Expand Down Expand Up @@ -300,6 +300,18 @@ PTF_TEST_CASE(HttpResponseParseStatusCodeTest)
PTF_ASSERT_EQUAL(pcpp::HttpResponseFirstLine::parseStatusCode(std::string("HTTP/x.y 477").c_str(), 12), pcpp::HttpResponseStatusCode::HttpStatus4xxCodeUnknown, enum);
PTF_ASSERT_EQUAL(pcpp::HttpResponseFirstLine::parseStatusCode(std::string("HTTP/x.y 577").c_str(), 12), pcpp::HttpResponseStatusCode::HttpStatus5xxCodeUnknown, enum);
PTF_ASSERT_EQUAL(pcpp::HttpResponseFirstLine::parseStatusCode(std::string("HTTP/x.y 600").c_str(), 12), pcpp::HttpResponseStatusCode::HttpStatusCodeUnknown, enum);


// test getMessage()
PTF_ASSERT_EQUAL(pcpp::HttpResponseFirstLine::parseStatusCode(std::string("HTTP/x.y 200").c_str(), 12).getMessage(), "OK");
PTF_ASSERT_EQUAL(pcpp::HttpResponseFirstLine::parseStatusCode(std::string("HTTP/x.y 404").c_str(), 12).getMessage(), "Not Found");

std::string testLine;
testLine = "HTTP/x.y 404 My Not Found\r\n";
PTF_ASSERT_EQUAL(pcpp::HttpResponseFirstLine::parseStatusCode(testLine.c_str(), testLine.size()).getMessage(), "My Not Found");
testLine = "HTTP/x.y 404 My Not Found Not Finished";
PTF_ASSERT_EQUAL(pcpp::HttpResponseFirstLine::parseStatusCode(testLine.c_str(), testLine.size()).getMessage(), "Not Found");

} // HttpResponseParseStatusCodeTest


Expand Down Expand Up @@ -440,10 +452,13 @@ PTF_TEST_CASE(HttpResponseLayerEditTest)

PTF_ASSERT_TRUE(responseLayer->getFirstLine()->isComplete());
responseLayer->getFirstLine()->setVersion(pcpp::OneDotOne);

// original status code is 404 Not Found
PTF_ASSERT_TRUE(responseLayer->getFirstLine()->setStatusCode(pcpp::HttpResponseStatusCode::Http505HTTPVersionNotSupported));
PTF_ASSERT_EQUAL(responseLayer->getFirstLine()->getStatusCode(), pcpp::HttpResponseStatusCode::Http505HTTPVersionNotSupported, enum);
PTF_ASSERT_EQUAL(responseLayer->getFirstLine()->getStatusCodeAsInt(), 505);
PTF_ASSERT_EQUAL(responseLayer->getFirstLine()->getStatusCodeString(), "HTTP Version Not Supported");

PTF_ASSERT_EQUAL(responseLayer->getFirstLine()->getStatusCodeString(), "HTTP Version Not Supported"); // customized message from packet

PTF_ASSERT_NOT_NULL(responseLayer->setContentLength(345));

Expand Down

0 comments on commit cc2608c

Please sign in to comment.