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

Porting HttpAnalyzer to C++11 #1196

Merged
merged 12 commits into from
Oct 3, 2023
18 changes: 10 additions & 8 deletions Examples/HttpAnalyzer/HttpStatsCollector.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once

#include <map>
#include <unordered_map>

#include <functional>
#include <sstream>
#include "HttpLayer.h"
#include "TcpLayer.h"
Expand Down Expand Up @@ -89,10 +91,10 @@ struct HttpMessageStats
*/
struct HttpRequestStats : HttpMessageStats
{
std::map<pcpp::HttpRequestLayer::HttpMethod, int> methodCount; // a map for counting the different HTTP methods seen in traffic
std::map<std::string, int> hostnameCount; // a map for counting the hostnames seen in traffic
std::unordered_map<pcpp::HttpRequestLayer::HttpMethod, int, std::hash<int> > methodCount; // a map for counting the different HTTP methods seen in traffic
std::unordered_map<std::string, int> hostnameCount; // a map for counting the hostnames seen in traffic

void clear()
void clear() override
{
HttpMessageStats::clear();
methodCount.clear();
Expand All @@ -106,13 +108,13 @@ struct HttpRequestStats : HttpMessageStats
*/
struct HttpResponseStats : HttpMessageStats
{
std::map<std::string, int> statusCodeCount; // a map for counting the different status codes seen in traffic
std::map<std::string, int> contentTypeCount; // a map for counting the content-types seen in traffic
std::unordered_map<std::string, int> statusCodeCount; // a map for counting the different status codes seen in traffic
std::unordered_map<std::string, int> contentTypeCount; // a map for counting the content-types seen in traffic
int numOfMessagesWithContentLength; // total number of responses containing the "content-length" field
int totalContentLengthSize; // total body size extracted by responses containing "content-length" field
double averageContentLengthSize; // average body size

void clear()
void clear() override
{
HttpMessageStats::clear();
numOfMessagesWithContentLength = 0;
Expand Down Expand Up @@ -461,7 +463,7 @@ class HttpStatsCollector
HttpResponseStats m_ResponseStats;
HttpResponseStats m_PrevResponseStats;

std::map<uint32_t, HttpFlowData> m_FlowTable;
std::unordered_map<uint32_t, HttpFlowData> m_FlowTable;

double m_LastCalcRateTime;
double m_StartTime;
Expand Down
138 changes: 53 additions & 85 deletions Examples/HttpAnalyzer/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
#include <iostream>
#include <sstream>


#define EXIT_WITH_ERROR(reason) do { \
printUsage(); \
std::cout << std::endl << "ERROR: " << reason << std::endl << std::endl; \
Expand Down Expand Up @@ -123,26 +122,19 @@ void printAppVersion()
*/
void listInterfaces()
{
const std::vector<pcpp::PcapLiveDevice*>& devList = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDevicesList();
const std::vector<pcpp::PcapLiveDevice*>& liveDevices = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDevicesList();

std::cout << std::endl << "Network interfaces:" << std::endl;
for (std::vector<pcpp::PcapLiveDevice*>::const_iterator iter = devList.begin(); iter != devList.end(); iter++)
{
std::cout << " -> Name: '" << (*iter)->getName() << "' IP address: " << (*iter)->getIPv4Address().toString() << std::endl;
for(const auto& device : liveDevices){
std::cout << " -> Name: '" << device->getName() << "' IP address: " << device->getIPv4Address().toString() << std::endl;
}
exit(0);
}


void printStatsHeadline(const std::string &description)
{
std::string underline;
for (size_t i = 0; i < description.length(); i++)
{
underline += "-";
}

std::cout << std::endl << description << std::endl << underline << std::endl << std::endl;
std::cout << std::endl << description << std::endl << std::string(description.length(),'-') << std::endl << std::endl;
}


Expand All @@ -169,81 +161,70 @@ void httpPacketArrive(pcpp::RawPacket* packet, pcpp::PcapLiveDevice* dev, void*
/**
* Print the method count table
*/
void printMethods(HttpRequestStats& reqStatscollector)
void printMethods(const HttpRequestStats& reqStatscollector)
jpcofr marked this conversation as resolved.
Show resolved Hide resolved
{
// create the table
std::vector<std::string> columnNames;
columnNames.push_back("Method");
columnNames.push_back("Count");
std::vector<int> columnsWidths;
columnsWidths.push_back(9);
columnsWidths.push_back(5);
std::vector<std::string> columnNames = {"Method", "Count"};
std::vector<int> columnsWidths = {9, 5};
pcpp::TablePrinter printer(columnNames, columnsWidths);


// go over the method count table and print each method and count
for(std::map<pcpp::HttpRequestLayer::HttpMethod, int>::iterator iter = reqStatscollector.methodCount.begin();
iter != reqStatscollector.methodCount.end();
iter++)
// Copy elements to a vector
std::vector<std::pair<pcpp::HttpRequestLayer::HttpMethod, int>> map2vec(reqStatscollector.methodCount.begin(), reqStatscollector.methodCount.end());
std::sort(map2vec.begin(), map2vec.end(),
[](const std::pair<pcpp::HttpRequestLayer::HttpMethod, int>& left,
const std::pair<pcpp::HttpRequestLayer::HttpMethod, int>& right) { return left.second > right.second; });
// go over the method count table, print each method and the aggregated figure
for (auto iter : map2vec)
{
std::stringstream values;

switch (iter->first)
switch (iter.first)
{
case pcpp::HttpRequestLayer::HttpGET:
values << "GET" << "|" << reqStatscollector.methodCount[pcpp::HttpRequestLayer::HttpGET];
printer.printRow(values.str(), '|');
values << "GET" << "|" << reqStatscollector.methodCount.at(pcpp::HttpRequestLayer::HttpGET);
break;
case pcpp::HttpRequestLayer::HttpPOST:
values << "POST" << "|" << reqStatscollector.methodCount[pcpp::HttpRequestLayer::HttpPOST];
printer.printRow(values.str(), '|');
values << "POST" << "|" << reqStatscollector.methodCount.at(pcpp::HttpRequestLayer::HttpPOST);
break;
case pcpp::HttpRequestLayer::HttpCONNECT:
values << "CONNECT" << "|" << reqStatscollector.methodCount[pcpp::HttpRequestLayer::HttpCONNECT];
printer.printRow(values.str(), '|');
values << "CONNECT" << "|" << reqStatscollector.methodCount.at(pcpp::HttpRequestLayer::HttpCONNECT);
break;
case pcpp::HttpRequestLayer::HttpDELETE:
values << "DELETE" << "|" << reqStatscollector.methodCount[pcpp::HttpRequestLayer::HttpDELETE];
printer.printRow(values.str(), '|');
values << "DELETE" << "|" << reqStatscollector.methodCount.at(pcpp::HttpRequestLayer::HttpDELETE);
break;
case pcpp::HttpRequestLayer::HttpHEAD:
values << "HEAD" << "|" << reqStatscollector.methodCount[pcpp::HttpRequestLayer::HttpHEAD];
printer.printRow(values.str(), '|');
values << "HEAD" << "|" << reqStatscollector.methodCount.at(pcpp::HttpRequestLayer::HttpHEAD);
break;
case pcpp::HttpRequestLayer::HttpOPTIONS:
values << "OPTIONS" << "|" << reqStatscollector.methodCount[pcpp::HttpRequestLayer::HttpOPTIONS];
printer.printRow(values.str(), '|');
values << "OPTIONS" << "|" << reqStatscollector.methodCount.at(pcpp::HttpRequestLayer::HttpOPTIONS);
break;
case pcpp::HttpRequestLayer::HttpPATCH:
values << "PATCH" << "|" << reqStatscollector.methodCount[pcpp::HttpRequestLayer::HttpPATCH];
printer.printRow(values.str(), '|');
values << "PATCH" << "|" << reqStatscollector.methodCount.at(pcpp::HttpRequestLayer::HttpPATCH);
break;
case pcpp::HttpRequestLayer::HttpPUT:
values << "PUT" << "|" << reqStatscollector.methodCount[pcpp::HttpRequestLayer::HttpPUT];
printer.printRow(values.str(), '|');
values << "PUT" << "|" << reqStatscollector.methodCount.at(pcpp::HttpRequestLayer::HttpPUT);
break;
case pcpp::HttpRequestLayer::HttpTRACE:
values << "TRACE" << "|" << reqStatscollector.methodCount[pcpp::HttpRequestLayer::HttpTRACE];
printer.printRow(values.str(), '|');
values << "TRACE" << "|" << reqStatscollector.methodCount.at(pcpp::HttpRequestLayer::HttpTRACE);
break;
default:
break;
}

if(iter.first != pcpp::HttpRequestLayer::HttpMethod::HttpMethodUnknown)
{
printer.printRow(values.str(), '|');
}

}
}


/**
* An auxiliary method for sorting the hostname count map. Used only in printHostnames()
*/
bool hostnameComparer(const std::pair<std::string, int>& first, const std::pair<std::string, int>& second)
bool hostnameComparer(const std::pair<std::string, int>& leftHost, const std::pair<std::string, int>& rightHost)
{
if (first.second == second.second)
{
return first.first > second.first;
}
return first.second > second.second;
return leftHost.second > rightHost.second || (leftHost.second == rightHost.second && leftHost.first > rightHost.first);
}

/**
Expand All @@ -252,26 +233,21 @@ bool hostnameComparer(const std::pair<std::string, int>& first, const std::pair<
void printHostnames(HttpRequestStats& reqStatscollector)
{
// create the table
std::vector<std::string> columnNames;
columnNames.push_back("Hostname");
columnNames.push_back("Count");
std::vector<int> columnsWidths;
columnsWidths.push_back(40);
columnsWidths.push_back(5);
std::vector<std::string> columnNames = {"Hostname", "Count"};
std::vector<int> columnsWidths = {40, 5};

pcpp::TablePrinter printer(columnNames, columnsWidths);

// sort the hostname count map so the most popular hostnames will be first
// since it's not possible to sort a std::map you must copy it to a std::vector and sort it then
std::vector<std::pair<std::string, int> > map2vec(reqStatscollector.hostnameCount.begin(), reqStatscollector.hostnameCount.end());
std::sort(map2vec.begin(),map2vec.end(), &hostnameComparer);
std::sort(map2vec.begin(), map2vec.end(), &hostnameComparer);

// go over all items (hostname + count) in the sorted vector and print them
for(std::vector<std::pair<std::string, int> >::iterator iter = map2vec.begin();
iter != map2vec.end();
iter++)
for(const auto& hostname : map2vec)
{
std::stringstream values;
values << iter->first << "|" << iter->second;
values << hostname.first << "|" << hostname.second;
printer.printRow(values.str(), '|');
}
}
Expand All @@ -280,24 +256,20 @@ void printHostnames(HttpRequestStats& reqStatscollector)
/**
* Print the status code count table
*/
void printStatusCodes(HttpResponseStats& resStatscollector)
void printStatusCodes(const HttpResponseStats& resStatscollector)
{
// create the table
std::vector<std::string> columnNames;
columnNames.push_back("Status Code");
columnNames.push_back("Count");
std::vector<int> columnsWidths;
columnsWidths.push_back(28);
columnsWidths.push_back(5);
std::vector<std::string> columnNames = {"Status Code", "Count"};
std::vector<int> columnsWidths = {28, 5};
pcpp::TablePrinter printer(columnNames, columnsWidths);

// go over the status code map and print each item
jpcofr marked this conversation as resolved.
Show resolved Hide resolved
for(std::map<std::string, int>::iterator iter = resStatscollector.statusCodeCount.begin();
iter != resStatscollector.statusCodeCount.end();
iter++)
// prints the status codes in lexical order
std::vector<std::pair<std::string, int>> map2vec(resStatscollector.statusCodeCount.begin(), resStatscollector.statusCodeCount.end());
std::sort(map2vec.begin(), map2vec.end(), [](const std::pair<std::string, int>& left, const std::pair<std::string, int>& right) { return left.first < right.first; });
for(const auto& statusCodeStat : map2vec)
{
std::stringstream values;
values << iter->first << "|" << iter->second;
values << statusCodeStat.first << "|" << statusCodeStat.second;
printer.printRow(values.str(), '|');
}
}
Expand All @@ -306,24 +278,20 @@ void printStatusCodes(HttpResponseStats& resStatscollector)
/**
* Print the content-type count table
*/
void printContentTypes(HttpResponseStats& resStatscollector)
void printContentTypes(const HttpResponseStats& resStatscollector)
{
// create the table
std::vector<std::string> columnNames;
columnNames.push_back("Content-type");
columnNames.push_back("Count");
std::vector<int> columnsWidths;
columnsWidths.push_back(30);
columnsWidths.push_back(5);
std::vector<std::string> columnNames = {"Content-type", "Count"};
std::vector<int> columnsWidths = {30, 5};
pcpp::TablePrinter printer(columnNames, columnsWidths);

// go over the status code map and print each item
for(std::map<std::string, int>::iterator iter = resStatscollector.contentTypeCount.begin();
iter != resStatscollector.contentTypeCount.end();
iter++)
// prints the content-types in lexical order
std::vector<std::pair<std::string, int>> map2vec(resStatscollector.contentTypeCount.begin(), resStatscollector.contentTypeCount.end());
std::sort(map2vec.begin(), map2vec.end(), [](const std::pair<std::string, int>& left, const std::pair<std::string, int>& right) { return left.first < right.first; });
for(const auto &contentTypeStat : map2vec)
{
std::stringstream values;
values << iter->first << "|" << iter->second;
values << contentTypeStat.first << "|" << contentTypeStat.second;
printer.printRow(values.str(), '|');
}
}
Expand Down