This commit is contained in:
Tim Blume 2020-09-03 00:23:37 +02:00
parent 741d5d96b2
commit aab0f45d61
7 changed files with 105 additions and 8 deletions

View file

@ -2,6 +2,26 @@
#include <mutex> #include <mutex>
#include <QDateTime> #include <QDateTime>
std::string HistoryModel::getRequestHeader(const HistoryItem &item) const
{
std::stringstream result;
result << item.method << " " << item.scheme << "://" << item.host << item.path << " " << item.request_http_version << "\n";
for(auto& [k,v] : item.request_headers) {
result << k << ": " << v << "\n";
}
return result.str();
}
std::string HistoryModel::getResponseHeader(const HistoryItem &item) const
{
std::stringstream result;
result << item.response_http_version << " " << item.status_code << " " << item.reason << "\n";
for(auto& [k,v] : item.response_headers) {
result << k << ": " << v << "\n";
}
return result.str();
}
HistoryModel::HistoryModel(QObject *parent) HistoryModel::HistoryModel(QObject *parent)
{ {
Q_UNUSED(parent); Q_UNUSED(parent);
@ -21,7 +41,7 @@ int HistoryModel::columnCount(const QModelIndex &parent) const
{ {
Q_UNUSED(parent); Q_UNUSED(parent);
return 7; return 11;
} }
QVariant HistoryModel::data(const QModelIndex &index, int role) const QVariant HistoryModel::data(const QModelIndex &index, int role) const
@ -64,6 +84,18 @@ QVariant HistoryModel::data(const QModelIndex &index, int role) const
case 6:{ case 6:{
return QString::number(item.size); return QString::number(item.size);
} }
case 7:{
return QString::fromStdString(getRequestHeader(item));
}
case 8:{
return QString::fromStdString(item.request_content);
}
case 9:{
return QString::fromStdString(getResponseHeader(item));
}
case 10:{
return QString::fromStdString(item.response_content);
}
} }
throw std::out_of_range("history model col"); throw std::out_of_range("history model col");
} catch (std::out_of_range const& exc) { } catch (std::out_of_range const& exc) {
@ -101,6 +133,18 @@ QVariant HistoryModel::headerData(int section, Qt::Orientation orientation, int
case 6: { case 6: {
return "size"; return "size";
} }
case 7: {
return "request headers";
}
case 8: {
return "request content";
}
case 9: {
return "response headers";
}
case 10: {
return "response content";
}
} }
} }
return QVariant(); return QVariant();

View file

@ -16,10 +16,12 @@ struct HistoryItem {
std::string reason; std::string reason;
double rtt = 0.0; double rtt = 0.0;
size_t size = 0; size_t size = 0;
std::string request_content; std::string request_http_version;
std::string response_content;
std::map<std::string, std::string> request_headers; std::map<std::string, std::string> request_headers;
std::string request_content;
std::string response_http_version;
std::map<std::string, std::string> response_headers; std::map<std::string, std::string> response_headers;
std::string response_content;
}; };
class HistoryModel : public QAbstractTableModel class HistoryModel : public QAbstractTableModel
@ -28,6 +30,8 @@ class HistoryModel : public QAbstractTableModel
private: private:
mutable std::mutex history_mutex; mutable std::mutex history_mutex;
std::vector<HistoryItem>* current_items = nullptr; std::vector<HistoryItem>* current_items = nullptr;
std::string getRequestHeader(const HistoryItem& item) const;
std::string getResponseHeader(const HistoryItem& item) const;
public: public:
HistoryModel(QObject *parent = nullptr); HistoryModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override;

View file

@ -45,9 +45,14 @@ void MainWindow::updateHistory() {
void MainWindow::on_selectionChange(const QItemSelection &selection) void MainWindow::on_selectionChange(const QItemSelection &selection)
{ {
if(!selection.indexes().isEmpty()) { if(!selection.indexes().isEmpty()) {
auto index = selection.indexes().value(0); auto index = selection.indexes().at(7);
qDebug() << history_proxy.itemData(index)[0].toInt(); ui->textEdit->setText(history_proxy.data(index).toString());
//ui->textEdit->setText(); index = selection.indexes().at(8);
ui->textEdit_2->setText(history_proxy.data(index).toString());
index = selection.indexes().at(9);
ui->textEdit_3->setText(history_proxy.data(index).toString());
index = selection.indexes().at(10);
ui->textEdit_4->setText(history_proxy.data(index).toString());
} }
} }

View file

@ -85,13 +85,37 @@ class LittleSnitchBridge:
self.q = Queue() self.q = Queue()
self.thread = NetworkThread("network", self.q) self.thread = NetworkThread("network", self.q)
self.thread.start() self.thread.start()
def request(self, flow): def request(self, flow):
self.q.put({'msg': 'request', 'flow': flow.get_state()}) self.q.put({'msg': 'request', 'flow': flow.get_state()})
def requestheaders(self, flow):
self.q.put({'msg': 'requestheaders', 'flow': flow.get_state()})
def response(self, flow): def response(self, flow):
self.q.put({'msg': 'response', 'flow': flow.get_state()}) self.q.put({'msg': 'response', 'flow': flow.get_state()})
def responseheaders(self, flow):
self.q.put({'msg': 'responseheaders', 'flow': flow.get_state()})
def error(self, flow):
self.q.put({'msg': 'error', 'flow': flow.get_state()})
def websocket_handshake(self):
self.q.put({'msg': 'websocket_handshake', 'flow': flow.get_state()})
def websocket_start(self, flow):
self.q.put({'msg': 'websocket_start', 'flow': flow.get_state()})
def websocket_message(self, flow):
self.q.put({'msg': 'websocket_message', 'flow': flow.get_state()})
def websocket_error(self, flow):
self.q.put({'msg': 'websocket_error', 'flow': flow.get_state()})
def websocket_end(self, flow):
self.q.put({'msg': 'websocket_end', 'flow': flow.get_state()})
addons = [ addons = [
LittleSnitchBridge() LittleSnitchBridge()
] ]

View file

@ -51,13 +51,31 @@ void NetworkThread::process() {
std::string msg_type; std::string msg_type;
if(!json_get(j, msg_type, "msg")) { if(!json_get(j, msg_type, "msg")) {
qDebug() << "broken message received " << response.to_string().c_str(); qDebug() << "broken message received " << response.to_string().c_str();
} else if(msg_type == "responseheaders") {
qDebug() << "received " << msg_type.c_str();
} else if(msg_type == "response") { } else if(msg_type == "response") {
qDebug() << "received " << msg_type.c_str(); qDebug() << "received " << msg_type.c_str();
emit httpMessage(j); emit httpMessage(j);
} else if(msg_type == "requestheaders") {
qDebug() << "received " << msg_type.c_str();
} else if(msg_type == "request") { } else if(msg_type == "request") {
qDebug() << "received " << msg_type.c_str(); qDebug() << "received " << msg_type.c_str();
} else if(msg_type == "ping") { } else if(msg_type == "ping") {
qDebug() << "received " << msg_type.c_str(); qDebug() << "received " << msg_type.c_str();
} else if(msg_type == "error") {
qDebug() << "received " << msg_type.c_str();
// websocket events
} else if(msg_type == "websocket_handshake") {
qDebug() << "received " << msg_type.c_str();
} else if(msg_type == "websocket_start") {
qDebug() << "received " << msg_type.c_str();
std::cout << std::setw(4) << j << "\n\n";
} else if(msg_type == "websocket_message") {
qDebug() << "received " << msg_type.c_str();
} else if(msg_type == "websocket_end") {
qDebug() << "received " << msg_type.c_str();
} else if(msg_type == "websocket_error") {
} else { } else {
qDebug() << "unknown or broken message type received: " << msg_type.c_str(); qDebug() << "unknown or broken message type received: " << msg_type.c_str();
} }

View file

@ -212,7 +212,9 @@ std::vector<HistoryItem>* Session::getHistoryItems() {
i.reason = std::string((const char*)sqlite3_column_text(stmt_get_all_history, j++)); i.reason = std::string((const char*)sqlite3_column_text(stmt_get_all_history, j++));
i.rtt = sqlite3_column_double(stmt_get_all_history, j++); i.rtt = sqlite3_column_double(stmt_get_all_history, j++);
i.size = sqlite3_column_int(stmt_get_all_history, j++); i.size = sqlite3_column_int(stmt_get_all_history, j++);
i.request_http_version = std::string((const char*)sqlite3_column_text(stmt_get_all_history, j++));
i.request_content = std::string((const char*)sqlite3_column_text(stmt_get_all_history, j++)); i.request_content = std::string((const char*)sqlite3_column_text(stmt_get_all_history, j++));
i.response_http_version = std::string((const char*)sqlite3_column_text(stmt_get_all_history, j++));
i.response_content = std::string((const char*)sqlite3_column_text(stmt_get_all_history, j++)); i.response_content = std::string((const char*)sqlite3_column_text(stmt_get_all_history, j++));
i.request_headers = getRequestHeader(i.id); i.request_headers = getRequestHeader(i.id);
i.response_headers = getResponseHeader(i.id); i.response_headers = getResponseHeader(i.id);

View file

@ -66,7 +66,7 @@ private:
const char* get_setting = R"rstr( SELECT value FROM setting WHERE key=?; )rstr"; const char* get_setting = R"rstr( SELECT value FROM setting WHERE key=?; )rstr";
const char* get_request_headers = R"rstr( SELECT * FROM response_header WHERE response_id=?; )rstr"; const char* get_request_headers = R"rstr( SELECT * FROM response_header WHERE response_id=?; )rstr";
const char* get_response_headers = R"rstr( SELECT * FROM request_header WHERE request_id=?; )rstr"; const char* get_response_headers = R"rstr( SELECT * FROM request_header WHERE request_id=?; )rstr";
const char* get_all_history = R"rstr( SELECT f.id,req.timestamp_start,req.method,req.scheme,req.host,req.port,req.path,res.status_code,res.reason,res.timestamp_end-res.timestamp_start,length(res.content),req.content,res.content FROM flow f JOIN request req ON f.request_id=req.id JOIN response res ON f.response_id=res.id; )rstr"; const char* get_all_history = R"rstr( SELECT f.id,req.timestamp_start,req.method,req.scheme,req.host,req.port,req.path,res.status_code,res.reason,res.timestamp_end-res.timestamp_start,length(res.content),req.http_version,req.content,res.http_version,res.content FROM flow f JOIN request req ON f.request_id=req.id JOIN response res ON f.response_id=res.id; )rstr";
const char* insert_request = R"rstr( INSERT INTO request (server_ip_address, tls, content, scheme, method, host, port, http_version, path, timestamp_start, timestamp_end, error) VALUES (?,?,?,?,?,?,?,?,?,?,?,?); )rstr"; const char* insert_request = R"rstr( INSERT INTO request (server_ip_address, tls, content, scheme, method, host, port, http_version, path, timestamp_start, timestamp_end, error) VALUES (?,?,?,?,?,?,?,?,?,?,?,?); )rstr";
const char* insert_request_header = R"rstr( INSERT INTO request_header (key, value, request_id) VALUES (?,?,?); )rstr"; const char* insert_request_header = R"rstr( INSERT INTO request_header (key, value, request_id) VALUES (?,?,?); )rstr";