1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
use crate::config::CONFIGURATION; use crate::utils::get_url_path_length; use crate::FeroxResponse; use std::any::Any; use std::fmt::Debug; // references: // https://dev.to/magnusstrale/rust-trait-objects-in-a-vector-non-trivial-4co5 // https://stackoverflow.com/questions/25339603/how-to-test-for-equality-between-trait-objects /// FeroxFilter trait; represents different types of possible filters that can be applied to /// responses pub trait FeroxFilter: Debug + Send + Sync { /// Determine whether or not this particular filter should be applied or not fn should_filter_response(&self, response: &FeroxResponse) -> bool; /// delegates to the FeroxFilter-implementing type which gives us the actual type of self fn box_eq(&self, other: &dyn Any) -> bool; /// gives us `other` as Any in box_eq fn as_any(&self) -> &dyn Any; } /// implementation of PartialEq, necessary long-form due to "trait cannot be made into an object" /// error when attempting to derive PartialEq on the trait itself impl PartialEq for Box<dyn FeroxFilter> { /// Perform a comparison of two implementors of the FeroxFilter trait fn eq(&self, other: &Box<dyn FeroxFilter>) -> bool { self.box_eq(other.as_any()) } } /// Data holder for two pieces of data needed when auto-filtering out wildcard responses /// /// `dynamic` is the size of the response that will later be combined with the length /// of the path of the url requested and used to determine interesting pages from custom /// 404s where the requested url is reflected back in the response /// /// `size` is size of the response that should be included with filters passed via runtime /// configuration and any static wildcard lengths. #[derive(Debug, Default, Clone, PartialEq)] pub struct WildcardFilter { /// size of the response that will later be combined with the length of the path of the url /// requested pub dynamic: u64, /// size of the response that should be included with filters passed via runtime configuration pub size: u64, } /// implementation of FeroxFilter for WildcardFilter impl FeroxFilter for WildcardFilter { /// Examine size, dynamic, and content_len to determine whether or not the response received /// is a wildcard response and therefore should be filtered out fn should_filter_response(&self, response: &FeroxResponse) -> bool { log::trace!("enter: should_filter_response({:?} {})", self, response); // quick return if dont_filter is set if CONFIGURATION.dont_filter { // --dont-filter applies specifically to wildcard filters, it is not a 100% catch all // for not filtering anything. As such, it should live in the implementation of // a wildcard filter return false; } if self.size > 0 && self.size == response.content_length() { // static wildcard size found during testing // size isn't default, size equals response length, and auto-filter is on log::debug!("static wildcard: filtered out {}", response.url()); log::trace!("exit: should_filter_response -> true"); return true; } if self.dynamic > 0 { // dynamic wildcard offset found during testing // I'm about to manually split this url path instead of using reqwest::Url's // builtin parsing. The reason is that they call .split() on the url path // except that I don't want an empty string taking up the last index in the // event that the url ends with a forward slash. It's ugly enough to be split // into its own function for readability. let url_len = get_url_path_length(&response.url()); if url_len + self.dynamic == response.content_length() { log::debug!("dynamic wildcard: filtered out {}", response.url()); log::trace!("exit: should_filter_response -> true"); return true; } } log::trace!("exit: should_filter_response -> false"); false } /// Compare one WildcardFilter to another fn box_eq(&self, other: &dyn Any) -> bool { other.downcast_ref::<Self>().map_or(false, |a| self == a) } /// Return self as Any for dynamic dispatch purposes fn as_any(&self) -> &dyn Any { self } } /// Simple implementor of FeroxFilter; used to filter out status codes specified using /// -C|--filter-status #[derive(Default, Debug, PartialEq)] pub struct StatusCodeFilter { /// Status code that should not be displayed to the user pub filter_code: u16, } /// implementation of FeroxFilter for StatusCodeFilter impl FeroxFilter for StatusCodeFilter { /// Check `filter_code` against what was passed in via -C|--filter-status fn should_filter_response(&self, response: &FeroxResponse) -> bool { log::trace!("enter: should_filter_response({:?} {})", self, response); if response.status().as_u16() == self.filter_code { log::debug!( "filtered out {} based on --filter-status of {}", response.url(), self.filter_code ); log::trace!("exit: should_filter_response -> true"); return true; } log::trace!("exit: should_filter_response -> false"); false } /// Compare one StatusCodeFilter to another fn box_eq(&self, other: &dyn Any) -> bool { other.downcast_ref::<Self>().map_or(false, |a| self == a) } /// Return self as Any for dynamic dispatch purposes fn as_any(&self) -> &dyn Any { self } }