Repository: emanuele-em/proxelar (language: rust)

Issue:
Filter request by method
It would be a good idea to add the possibility of filtering requests by method


Discussion / hints:

Fix patch:
diff --git a/mitm_proxy/src/mitm_proxy.rs b/mitm_proxy/src/mitm_proxy.rs
index 30584eb..84d9ba0 100644
--- a/mitm_proxy/src/mitm_proxy.rs
+++ b/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},
@@ -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)]
@@ -40,8 +40,41 @@ 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,
 }
 
@@ -49,6 +82,7 @@ impl MitmProxyState {
     fn new() -> Self {
         Self {
             selected_request: None,
+            selected_request_method: MethodFilter::All,
             detail_option: InfoOptions::Request,
         }
     }
@@ -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);
+                            }
+                        });
+                    })
+                }
             });
     }
 
@@ -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();
                     }
diff --git a/mitm_proxy/src/requests.rs b/mitm_proxy/src/requests.rs
index 5b9bf17..a081192 100644
--- a/mitm_proxy/src/requests.rs
+++ b/mitm_proxy/src/requests.rs
@@ -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,
@@ -15,6 +16,7 @@ struct Request {
 
 impl Request {
     fn new(
+        http_method: Method,
         method: String,
         uri: String,
         version: String,
@@ -23,6 +25,7 @@ impl Request {
         time: i64,
     ) -> Self {
         Self {
+            http_method,
             method,
             uri,
             version,
@@ -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(),
@@ -180,6 +184,14 @@ 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",
@@ -187,7 +199,7 @@ impl RequestInfo {
         });
     }
 
-    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;
diff --git a/proxyapi/src/output.rs b/proxyapi/src/output.rs
index 641d552..055874e 100644
--- a/proxyapi/src/output.rs
+++ b/proxyapi/src/output.rs
@@ -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};
@@ -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(),
@@ -91,6 +92,7 @@ impl HttpHandler for Output {
 
 #[derive(Clone, Debug)]
 pub struct OutputRequest {
+    http_method: Method,
     method: String,
     uri: String,
     version: String,
@@ -101,6 +103,7 @@ pub struct OutputRequest {
 
 impl OutputRequest {
     fn new(
+        http_method: Method,
         method: String,
         uri: String,
         version: String,
@@ -109,6 +112,7 @@ impl OutputRequest {
         time: i64,
     ) -> Self {
         Self {
+            http_method,
             method,
             uri,
             version,
@@ -118,6 +122,10 @@ impl OutputRequest {
         }
     }
 
+    pub fn http_method(&self) -> &Method {
+        &self.http_method
+    }
+
     pub fn method(&self) -> &String {
         &self.method
     }


Test patch: