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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement filtering requests by method #19

Merged
merged 2 commits into from Feb 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
94 changes: 79 additions & 15 deletions mitm_proxy/src/mitm_proxy.rs
@@ -1,4 +1,4 @@
use std::sync::mpsc::Receiver;
use std::{sync::mpsc::Receiver, fmt::{Display, format}, default};

use crate::{
requests::{InfoOptions, RequestInfo},
Expand All @@ -8,13 +8,13 @@ use crate::{
use eframe::{
egui::{
self, FontData, FontDefinitions, FontFamily, Grid, Layout, ScrollArea, Style, TextStyle::*,
TopBottomPanel, Visuals,
TopBottomPanel, Visuals, RichText, ComboBox,
},
epaint::FontId,
Frame,
};
use egui_extras::{Column, TableBuilder};
use proxyapi::*;
use proxyapi::{*, hyper::Method};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
Expand All @@ -40,15 +40,49 @@ impl Default for MitmProxyConfig {
}
}


#[derive(Debug,Default,PartialEq, Eq)]
pub enum MethodFilter {
#[default]
All,
Only(Method),
}
impl MethodFilter{
const METHODS: [(&'static str,Self);10]=[
("All",MethodFilter::All),
("GET",MethodFilter::Only(Method::GET)),
("POST",MethodFilter::Only(Method::POST)),
("PUT",MethodFilter::Only(Method::PUT)),
("DELETE",MethodFilter::Only(Method::DELETE)),
("PATCH",MethodFilter::Only(Method::PATCH)),
("HEAD",MethodFilter::Only(Method::HEAD)),
("OPTIONS",MethodFilter::Only(Method::OPTIONS)),
("CONNECT",MethodFilter::Only(Method::CONNECT)),
("TRACE",MethodFilter::Only(Method::TRACE)),
];
}
impl Display for MethodFilter {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Self::Only(method) = self {
Display::fmt(method, f)
}else {
f.write_str("All")
}
}
}


struct MitmProxyState {
selected_request: Option<usize>,
selected_request_method: MethodFilter,
detail_option: InfoOptions,
}

impl MitmProxyState {
fn new() -> Self {
Self {
selected_request: None,
selected_request_method: MethodFilter::All,
detail_option: InfoOptions::Request,
}
}
Expand Down Expand Up @@ -155,18 +189,31 @@ impl MitmProxy {

header.col(|_ui| ());
})
.body(|body| {
body.rows(text_height, self.requests.len(), |row_index, mut row| {
self.requests
.get_mut(row_index)
.expect("Problem with index")
.render_row(&mut row);
row.col(|ui| {
if ui.button("馃攷").clicked() {
self.state.selected_request = Some(row_index);
}
});
})
.body(|mut body| {
if let MethodFilter::Only(filter_method) = &self.state.selected_request_method {
for (row_index, request) in self.requests.iter().enumerate().filter(|r|r.1.should_show(&filter_method)) {
body.row(text_height, |mut row|{
request.render_row(&mut row);
row.col(|ui| {
if ui.button("馃攷").clicked() {
self.state.selected_request = Some(row_index);
}
});
});
}
}else{
body.rows(text_height, self.requests.len(), |row_index, mut row| {
self.requests
.get_mut(row_index)
.expect("Problem with index")
.render_row(&mut row);
row.col(|ui| {
if ui.button("馃攷").clicked() {
self.state.selected_request = Some(row_index);
}
});
})
}
});
}

Expand Down Expand Up @@ -247,6 +294,23 @@ impl MitmProxy {
})
.on_hover_text("Toggle theme");



const COMBOBOX_TEXT_SIZE:f32=15.;
ComboBox::from_label("")
.selected_text(RichText::new(format!("{} Requests",&self.state.selected_request_method)).size(COMBOBOX_TEXT_SIZE))
.wrap(false)
.show_ui(ui, |ui| {
ui.style_mut().wrap = Some(false);
for (method_str, method) in MethodFilter::METHODS {
ui.selectable_value(
&mut self.state.selected_request_method,
method,
RichText::new(method_str).size(COMBOBOX_TEXT_SIZE)
);
}
});

if close_btn.clicked() {
frame.close();
}
Expand Down
16 changes: 14 additions & 2 deletions mitm_proxy/src/requests.rs
Expand Up @@ -2,9 +2,10 @@ use std::collections::HashMap;

use eframe::egui::{self};
use egui_extras::TableRow;
use proxyapi::*;
use proxyapi::{*, hyper::Method};

struct Request {
http_method: Method,
method: String,
uri: String,
version: String,
Expand All @@ -15,6 +16,7 @@ struct Request {

impl Request {
fn new(
http_method: Method,
method: String,
uri: String,
version: String,
Expand All @@ -23,6 +25,7 @@ impl Request {
time: i64,
) -> Self {
Self {
http_method,
method,
uri,
version,
Expand Down Expand Up @@ -93,6 +96,7 @@ impl From<Output> for RequestInfo {
fn from(value: Output) -> Self {
let request = match value.req() {
Some(r) => Some(Request::new(
r.http_method().clone(),
r.method().to_string(),
r.uri().to_string(),
r.version().to_string(),
Expand Down Expand Up @@ -180,14 +184,22 @@ impl RequestInfo {
}
}

pub fn should_show(&self, method:&Method)->bool {
if let Some(req) = &self.request {
req.http_method == method
}else{
false
}
}

pub fn show_details(&mut self, ui: &mut egui::Ui) {
ui.label(match &self.details {
Some(_) => "Some details",
None => "No details",
});
}

pub fn render_row(&mut self, row: &mut TableRow) {
pub fn render_row(&self, row: &mut TableRow) {
let req = self.request.as_ref().unwrap();
let res = self.response.as_ref().unwrap();
let time = (res.time as f64 - req.time as f64) * 10_f64.powf(-9.0) as f64;
Expand Down
10 changes: 9 additions & 1 deletion proxyapi/src/output.rs
Expand Up @@ -2,7 +2,7 @@ use std::{collections::HashMap, sync::mpsc::SyncSender};


use async_trait::async_trait;
use http::{HeaderMap, Version, Response, Request};
use http::{HeaderMap, Version, Response, Request, Method};
use hyper::{Body};

use crate::{HttpHandler, HttpContext, RequestResponse};
Expand Down Expand Up @@ -55,6 +55,7 @@ impl HttpHandler for Output {
async fn handle_request(&mut self, _ctx: &HttpContext, req: Request<Body>, ) -> RequestResponse {
println!("request{:?}\n", req);
let output_request = OutputRequest::new(
req.method().clone(),
req.method().to_string(),
req.uri().to_string(),
req.version().to_string(),
Expand Down Expand Up @@ -91,6 +92,7 @@ impl HttpHandler for Output {

#[derive(Clone, Debug)]
pub struct OutputRequest {
http_method: Method,
method: String,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, I wasn't sure why the items were converted into Strings. My guess is to stop heap allocations each frame or a similar performance concern, but if not, then maybe the http_method field is an adequate replacement for the existing methodfield.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A rude truth: string conversions sucks and it is bad practice in this case but it was my first approach to gui and as the first versions was comfortable. One fo the next steps is to avoid the String conversion on everything. For now thank you very much for your effort, i review the code today.

uri: String,
version: String,
Expand All @@ -101,6 +103,7 @@ pub struct OutputRequest {

impl OutputRequest {
fn new(
http_method: Method,
method: String,
uri: String,
version: String,
Expand All @@ -109,6 +112,7 @@ impl OutputRequest {
time: i64,
) -> Self {
Self {
http_method,
method,
uri,
version,
Expand All @@ -118,6 +122,10 @@ impl OutputRequest {
}
}

pub fn http_method(&self) -> &Method {
&self.http_method
}

pub fn method(&self) -> &String {
&self.method
}
Expand Down