mirror of
https://github.com/epi052/feroxbuster.git
synced 2026-05-23 13:11:12 -03:00
added rwlock to stats
This commit is contained in:
@@ -574,7 +574,7 @@ pub struct FeroxState {
|
||||
/// Known responses
|
||||
responses: &'static FeroxResponses,
|
||||
|
||||
statistics: Arc<Stats>,
|
||||
statistics: Arc<RwLock<Stats>>,
|
||||
}
|
||||
|
||||
/// FeroxSerialize implementation for FeroxState
|
||||
@@ -594,7 +594,7 @@ impl FeroxSerialize for FeroxState {
|
||||
/// that representation to seconds and then wait for those seconds to elapse. Once that period
|
||||
/// of time has elapsed, kill all currently running scans and dump a state file to disk that can
|
||||
/// be used to resume any unfinished scan.
|
||||
pub async fn start_max_time_thread(time_spec: &str, stats: Arc<Stats>) {
|
||||
pub async fn start_max_time_thread(time_spec: &str, stats: Arc<RwLock<Stats>>) {
|
||||
log::trace!("enter: start_max_time_thread({})", time_spec);
|
||||
|
||||
// as this function has already made it through the parser, which calls is_match on
|
||||
@@ -636,7 +636,7 @@ pub async fn start_max_time_thread(time_spec: &str, stats: Arc<Stats>) {
|
||||
}
|
||||
|
||||
/// Writes the current state of the program to disk (if save_state is true) and then exits
|
||||
fn sigint_handler(stats: Arc<Stats>) {
|
||||
fn sigint_handler(stats: Arc<RwLock<Stats>>) {
|
||||
log::trace!("enter: sigint_handler");
|
||||
|
||||
let ts = SystemTime::now()
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
// todo needs to be serializable and added to scan save/resume/output
|
||||
// todo consider batch size for stats update/display (if display is used)
|
||||
// todo are there more metrics to capture?
|
||||
// - domains redirected to?
|
||||
// - number of links extracted vs busted?
|
||||
// - number of busted?
|
||||
// - number of borked urls?
|
||||
// - total time to run
|
||||
// - time per directory
|
||||
// - wildcards filtered
|
||||
// todo integration test that hits some/all of the errors in make_request
|
||||
// todo create a summary report to be shown when the scan ends, should present the accumulated data in a way that makes interpretation easy
|
||||
|
||||
@@ -22,7 +20,7 @@ use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::{
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
Arc,
|
||||
Arc, RwLock,
|
||||
};
|
||||
use tokio::{
|
||||
sync::mpsc::{self, UnboundedReceiver, UnboundedSender},
|
||||
@@ -52,7 +50,7 @@ macro_rules! atomic_load {
|
||||
/// Data collection of statistics related to a scan
|
||||
#[derive(Deserialize, Debug, Serialize)]
|
||||
pub struct Stats {
|
||||
#[serde(rename = "type", default = "stats_kind")]
|
||||
#[serde(rename = "type")]
|
||||
/// Name of this type of struct, used for serialization, i.e. `{"type":"statistics"}`
|
||||
kind: String,
|
||||
|
||||
@@ -60,7 +58,7 @@ pub struct Stats {
|
||||
timeouts: AtomicUsize,
|
||||
|
||||
/// tracker for total number of requests sent by the client
|
||||
requests: AtomicUsize,
|
||||
requests: usize,
|
||||
|
||||
/// tracker for total number of requests expected to send if the scan runs to completion
|
||||
///
|
||||
@@ -103,11 +101,9 @@ pub struct Stats {
|
||||
|
||||
/// tracker for overall number of all filtered responses
|
||||
responses_filtered: AtomicUsize,
|
||||
}
|
||||
|
||||
/// default value for `Stats::kind`
|
||||
fn stats_kind() -> String {
|
||||
String::from("statistics")
|
||||
/// tracker for each directory's total scan time in seconds as a float
|
||||
directory_scan_times: Vec<f64>,
|
||||
}
|
||||
|
||||
/// Default implementation for Stats
|
||||
@@ -130,6 +126,7 @@ impl Default for Stats {
|
||||
status_403s: Default::default(),
|
||||
wildcards_filtered: Default::default(),
|
||||
responses_filtered: Default::default(),
|
||||
directory_scan_times: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,6 +245,7 @@ impl Stats {
|
||||
}
|
||||
}
|
||||
|
||||
/// Build out the summary string of a `Stats` object
|
||||
fn summary(&self) -> String {
|
||||
let results_bottom = "───────────────────────────┬──────────────────────";
|
||||
let results_top = "──────────────────────────────────────────────────";
|
||||
@@ -264,15 +262,13 @@ impl Stats {
|
||||
|
||||
let mut lines = Vec::new();
|
||||
|
||||
let results_header = format!(" 📊{}📊", pad_str("Results", 44, Alignment::Center, None));
|
||||
let padded_results = pad_str("Results", 44, Alignment::Center, None);
|
||||
let results_header = format!("\u{0020}📊{}📊\u{0020}", padded_results);
|
||||
|
||||
lines.push(results_top.to_string());
|
||||
lines.push(results_header);
|
||||
lines.push(results_bottom.to_string());
|
||||
|
||||
// printer.println(format!("{}", results_top));
|
||||
// printer.println(results_header);
|
||||
// printer.println(format!("{}", results_bottom));
|
||||
|
||||
let responses = format_summary_item!(
|
||||
"Requests Sent / Expected",
|
||||
format!(
|
||||
@@ -306,6 +302,8 @@ impl Stats {
|
||||
}
|
||||
}
|
||||
|
||||
// todo scan time stuff
|
||||
|
||||
lines.push(bottom.to_string());
|
||||
|
||||
lines.join("\n")
|
||||
@@ -392,7 +390,7 @@ pub enum StatField {
|
||||
/// The consumer simply receives `StatCommands` and updates the given `Stats` object as appropriate
|
||||
pub async fn spawn_statistics_handler(
|
||||
mut stats_channel: UnboundedReceiver<StatCommand>,
|
||||
stats: Arc<Stats>,
|
||||
stats: Arc<RwLock<Stats>>,
|
||||
) {
|
||||
log::trace!(
|
||||
"enter: spawn_statistics_handler({:?}, {:?})",
|
||||
@@ -403,7 +401,7 @@ pub async fn spawn_statistics_handler(
|
||||
while let Some(command) = stats_channel.recv().await {
|
||||
match command as StatCommand {
|
||||
StatCommand::AddError(err) => {
|
||||
stats.add_error(err);
|
||||
stats.read().unwrap().add_error(err);
|
||||
}
|
||||
StatCommand::AddStatus(status) => {
|
||||
stats.add_status_code(status);
|
||||
@@ -422,10 +420,14 @@ pub async fn spawn_statistics_handler(
|
||||
|
||||
/// Initialize new `Stats` object and the sc side of an mpsc channel that is responsible for
|
||||
/// updates to the aforementioned object.
|
||||
pub fn initialize() -> (Arc<Stats>, UnboundedSender<StatCommand>, JoinHandle<()>) {
|
||||
pub fn initialize() -> (
|
||||
Arc<RwLock<Stats>>,
|
||||
UnboundedSender<StatCommand>,
|
||||
JoinHandle<()>,
|
||||
) {
|
||||
log::trace!("enter: initialize");
|
||||
|
||||
let stats_tracker = Arc::new(Stats::default());
|
||||
let stats_tracker = Arc::new(RwLock::new(Stats::default()));
|
||||
let cloned = stats_tracker.clone();
|
||||
let (tx_stats, rx_stats): FeroxChannel<StatCommand> = mpsc::unbounded_channel();
|
||||
let stats_thread =
|
||||
@@ -446,7 +448,11 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
/// simple helper to reduce code reuse
|
||||
fn setup_stats_test() -> (Arc<Stats>, UnboundedSender<StatCommand>, JoinHandle<()>) {
|
||||
fn setup_stats_test() -> (
|
||||
Arc<RwLock<Stats>>,
|
||||
UnboundedSender<StatCommand>,
|
||||
JoinHandle<()>,
|
||||
) {
|
||||
initialize()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user