Skip to content

Commit

Permalink
Ported HttpAnalyzer to C++11
Browse files Browse the repository at this point in the history
Other: Updates to the documentation
  • Loading branch information
jpcofr committed Sep 17, 2023
1 parent 399afa5 commit d52705b
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 89 deletions.
18 changes: 10 additions & 8 deletions Examples/HttpAnalyzer/HttpStatsCollector.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <map>
#include <unordered_map>
#include <functional>
#include <sstream>
#include "HttpLayer.h"
#include "TcpLayer.h"
Expand All @@ -9,6 +10,7 @@
#include "PacketUtils.h"
#include "SystemUtils.h"


/**
* An auxiliary struct for encapsulating rate stats
*/
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
122 changes: 41 additions & 81 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,66 @@ void httpPacketArrive(pcpp::RawPacket* packet, pcpp::PcapLiveDevice* dev, void*
/**
* Print the method count table
*/
void printMethods(HttpRequestStats& reqStatscollector)
void printMethods(const HttpRequestStats& reqStatscollector)
{
// 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++)
for (auto iter : reqStatscollector.methodCount)
{
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[pcpp::HttpRequestLayer::HttpGET]; */
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)
{
if (first.second == second.second)
{
return first.first > second.first;
}
return first.second > second.second;
return first.second > second.second || (first.second == second.second && first.first > second.first);
}

/**
Expand All @@ -252,26 +229,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 +252,18 @@ 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 = {12, 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.statusCodeCount.begin();
iter != resStatscollector.statusCodeCount.end();
iter++)
for(const auto& statusCodeStat : resStatscollector.statusCodeCount)
{
std::stringstream values;
values << iter->first << "|" << iter->second;
values << statusCodeStat.first << "|" << statusCodeStat.second;
printer.printRow(values.str(), '|');
}
}
Expand All @@ -306,24 +272,18 @@ 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++)
for(const auto &contentTypeStat : resStatscollector.contentTypeCount)
{
std::stringstream values;
values << iter->first << "|" << iter->second;
values << contentTypeStat.first << "|" << contentTypeStat.second;
printer.printRow(values.str(), '|');
}
}
Expand Down

0 comments on commit d52705b

Please sign in to comment.