Skip to content

Commit

Permalink
fixes #1 change the design, better type-safety
Browse files Browse the repository at this point in the history
rename "message parser" to "custom streams store", and make it stateful
-- it holds the messages data. This solves the type-safety issues I've
been having. Better design overall.
  • Loading branch information
emmanueltouzery committed Jan 30, 2022
1 parent 73703e8 commit c72b596
Show file tree
Hide file tree
Showing 22 changed files with 1,698 additions and 1,522 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "hotwire"
version = "0.2.0"
authors = ["Emmanuel Touzery <[email protected]>"]
edition = "2018"
edition = "2021"

[build-dependencies]
reqwest = { version = "0.11.9", features = ["blocking"] }
Expand Down
121 changes: 121 additions & 0 deletions src/custom_streams_store.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
use crate::icons::Icon;
use crate::search_expr;
use crate::tshark_communication::{NetworkPort, TSharkPacket, TcpStreamId};
use crate::widgets::win;
use crate::BgFunc;
use gtk::prelude::*;
use std::net::IpAddr;
use std::sync::mpsc;

#[derive(Copy, Clone)]
pub struct ClientServerInfo {
// need to say who is the server. i have 50:50 chance
// that the first message that was capture is from the
// client contacting the server, or the server responding
// to the client
pub server_ip: IpAddr,
pub server_port: NetworkPort,
pub client_ip: IpAddr,
}

pub const TREE_STORE_STREAM_ID_COL_IDX: u32 = 2;
pub const TREE_STORE_MESSAGE_INDEX_COL_IDX: u32 = 3;

/// A custom streams store parses, stores & displays messages related to
/// a certain protocol, for instance HTTP. The custom streams store deals with
/// parsing packets, storing them by TCP stream as well as displaying them.
///
/// The first step is to take TSharkPackets and build streams (list of
/// messages and meta-data) from it.
///
/// So, one TSharkPacket may cause you to create zero, one, or multiple
/// messages in your stream. You also must try to populate the
/// ClientServerInfo, letting hotwire know who is the server and who is
/// the client, based on your protocol knowledge.
/// Because we can parse realtime traffic that is being recorded live,
/// you don't get the list of packets all at once, rather you can store
/// your state in your 'globals' object, and you get fed new packets
/// through 'add_to_packet'. After the last packet, 'finish_stream' will
/// be called for you to clean up your state.
///
/// Then there are methods for populating the GUI treeview, the details
/// area, and others.
pub trait CustomStreamsStore {
fn is_my_message(&self, msg: &TSharkPacket) -> bool;

/// by restricting tshark to only the packets we can decode,
/// we can possibly speed up things... so tell me how to filter
/// for your protocol (for instance 'http2', 'pgsql' and so on)
fn tshark_filter_string(&self) -> &'static str;

fn protocol_icon(&self) -> Icon;

fn protocol_name(&self) -> &'static str;

fn tcp_stream_ids(&self) -> Vec<TcpStreamId>;

fn has_stream_id(&self, stream_id: TcpStreamId) -> bool;

fn is_empty(&self) -> bool;

fn stream_client_server(&self, stream_id: TcpStreamId) -> Option<ClientServerInfo>;

// parsing
fn reset(&mut self);

fn stream_message_count(&self, stream_id: TcpStreamId) -> Option<usize>;
fn stream_summary_details(&self, stream_id: TcpStreamId) -> Option<&str>;

fn add_to_stream(
&mut self,
stream_id: TcpStreamId,
new_packet: TSharkPacket,
) -> Result<Option<ClientServerInfo>, String>;
fn finish_stream(&mut self, stream_id: TcpStreamId) -> Result<(), String>;

// treeview
fn prepare_treeview(&self, tv: &gtk::TreeView);
fn get_empty_liststore(&self) -> gtk::ListStore;
fn populate_treeview(&self, ls: &gtk::ListStore, session_id: TcpStreamId, start_idx: i32);
fn end_populate_treeview(&self, tv: &gtk::TreeView, ls: &gtk::ListStore);

fn display_in_details_widget(
&self,
bg_sender: mpsc::Sender<BgFunc>,
stream_id: TcpStreamId,
msg_idx: usize,
);

// details
fn requests_details_overlay(&self) -> bool;
fn add_details_to_scroll(
&mut self,
parent: &gtk::ScrolledWindow,
overlay: Option<&gtk::Overlay>,
bg_sender: mpsc::Sender<BgFunc>,
win_msg_sender: relm::StreamHandle<win::Msg>,
);

// search
fn supported_filter_keys(&self) -> &'static [&'static str];
fn matches_filter(
&self,
filter: &search_expr::SearchOpExpr,
model: &gtk::TreeModel,
iter: &gtk::TreeIter,
) -> bool;
}

pub fn get_message_helper(model: &gtk::TreeModel, iter: &gtk::TreeIter) -> (TcpStreamId, u32) {
let stream_id = TcpStreamId(
model
.value(iter, TREE_STORE_STREAM_ID_COL_IDX as i32)
.get::<u32>()
.unwrap(),
);
let idx = model
.value(iter, TREE_STORE_MESSAGE_INDEX_COL_IDX as i32)
.get::<u32>()
.unwrap();
(stream_id, idx)
}
6 changes: 3 additions & 3 deletions src/http/http_body_widget.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::code_formatting;
use super::http_message_parser;
use super::http_message_parser::{HttpBody, HttpRequestResponseData};
use super::http_streams_store;
use super::http_streams_store::{HttpBody, HttpRequestResponseData};
use crate::widgets::win;
use crate::BgFunc;
use gdk_pixbuf::prelude::*;
Expand Down Expand Up @@ -192,7 +192,7 @@ impl Widget for HttpBodyWidget {
.data
.as_ref()
.and_then(|d| {
http_message_parser::get_http_header_value(&d.headers, "Content-Disposition")
http_streams_store::get_http_header_value(&d.headers, "Content-Disposition")
})
.and_then(|d| {
d.strip_prefix("attachment: filename=\"")
Expand Down
17 changes: 4 additions & 13 deletions src/http/http_details_widget.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use super::http_body_widget;
use super::http_body_widget::HttpBodyWidget;
use super::http_message_parser::{HttpMessageData, HttpRequestResponseData};
use super::http_streams_store::{HttpMessageData, HttpRequestResponseData};
use crate::icons::Icon;
use crate::message_parser::{MessageData, MessageInfo};
use crate::tshark_communication::TcpStreamId;
use crate::widgets::comm_info_header;
use crate::widgets::comm_info_header::CommInfoHeader;
Expand All @@ -18,7 +17,7 @@ use std::sync::mpsc;

#[derive(Msg, Debug)]
pub enum Msg {
DisplayDetails(mpsc::Sender<BgFunc>, MessageInfo),
DisplayDetails(mpsc::Sender<BgFunc>, IpAddr, TcpStreamId, HttpMessageData),
RemoveFormatToggled,
CopyContentsClick,
}
Expand Down Expand Up @@ -119,15 +118,8 @@ impl Widget for HttpCommEntry {
fn update(&mut self, event: Msg) {
// dbg!(&event);
match event {
Msg::DisplayDetails(
..,
MessageInfo {
client_ip,
stream_id,
message_data: MessageData::Http(msg),
},
) => {
self.model.data = msg;
Msg::DisplayDetails(.., client_ip, stream_id, message_data) => {
self.model.data = message_data;
self.streams
.comm_info_header
.emit(comm_info_header::Msg::Update(client_ip, stream_id));
Expand Down Expand Up @@ -204,7 +196,6 @@ impl Widget for HttpCommEntry {
}
self.model.options_popover.popdown();
}
_ => {}
}
}

Expand Down
Loading

0 comments on commit c72b596

Please sign in to comment.