### Initialize ProductScheduler Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/schedulers/product.rs.html Example showing the basic setup and import requirements for a ProductScheduler instance. ```rust use feroxfuzz::schedulers::{Scheduler, ProductScheduler}; use feroxfuzz::prelude::*; use feroxfuzz::corpora::{RangeCorpus, Wordlist}; # fn main() -> Result<(), Box> { ``` -------------------------------- ### Observer Implementation Examples Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/observers/mod.rs.html Provides examples of how to implement observers and observer collections, including recursive calls. ```APIDOC ## Observer Implementation Examples ### Description Demonstrates the implementation of the `Observers` trait for empty tuples and tuples of observers, enabling recursive hook execution. ### Implementations #### `Observers for ()` - **Description**: Implements `Observers` for an empty tuple, serving as the base case for recursion. - **Type Parameters**: - `R`: The type of the `Response`. #### `Observers for (Head, Tail)` - **Description**: Implements `Observers` for a tuple of `Head` and `Tail`, recursively calling hooks on both. - **Type Parameters**: - `R`: The type of the `Response`. - `Head`: The first observer in the tuple, must implement `Named` and `ObserverHooks`. - `Tail`: The rest of the observers, must implement `Observers` and `ObserversList`. - **Methods**: - `call_pre_send_hooks(&mut self, request: &Request)`: Calls `pre_send_hook` on `Head` and then recursively calls `call_pre_send_hooks` on `Tail`. - `call_post_send_hooks(&mut self, response: R)`: Calls `post_send_hook` on `Head` and then recursively calls `call_post_send_hooks` on `Tail`. ``` -------------------------------- ### ProductScheduler Example Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/schedulers/struct.ProductScheduler.html An example demonstrating the creation and usage of ProductScheduler to iterate through a Cartesian product of corpora. ```APIDOC ## GET /api/users/{id} ### Description Retrieves details for a specific user by their ID. ### Method GET ### Endpoint /api/users/{id} ### Parameters #### Path Parameters - **id** (integer) - Required - The unique identifier of the user to retrieve. ### Response #### Success Response (200) - **id** (integer) - The unique identifier for the user. - **username** (string) - The username of the user. - **email** (string) - The email address of the user. #### Response Example ```json { "id": 123, "username": "johndoe", "email": "john.doe@example.com" } ``` ``` -------------------------------- ### RangeCorpus Usage Example Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/corpora/range.rs.html Example demonstrating the creation and usage of a RangeCorpus. ```APIDOC ## RangeCorpus Usage ### Description This example shows how to initialize and use the `RangeCorpus`. ### Method `GET` (Conceptual - this is for accessing data from the corpus) ### Endpoint N/A (Instance method) ### Parameters N/A ### Request Body N/A ### Request Example ```rust // Assuming RangeBuilder is imported and configured let corpus = RangeBuilder::new() .start(10) .stop(20) .step(2) .name("even_numbers") .build() .expect("Failed to build RangeCorpus"); // Accessing items from the corpus let first_item = corpus.get(0); let third_item = corpus.get(2); println!("First item: {:?}", first_item); println!("Third item: {:?}", third_item); ``` ### Response #### Success Response (200) - **String** - The item at the specified index. #### Response Example ``` First item: Some("10") Third item: Some("14") ``` ``` -------------------------------- ### AsyncFuzzer Builder with TTTF Configuration Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/fuzzers/async_builder.rs.html Configures the AsyncFuzzer with a client, request, corpus, scheduler, mutator, observers, and processors. This example demonstrates the inclusion of request processors in the fuzzer setup. ```rust fn test_async_fuzzer_builder_tttf() { let req_client = reqwest::Client::builder().build().unwrap(); let client = AsyncClient::with_client(req_client); let request = Request::from_url("http://localhost:8000/", None).unwrap(); let corpus = Wordlist::with_words(["hi"]).name("corpus").build(); let scheduler = OrderedScheduler::new(SharedState::with_corpus(corpus)).unwrap(); let mutator = ReplaceKeyword::new(&"RANGE1", "range1"); let _tested = AsyncFuzzer::new(10) .client(client) .request(request) .scheduler(scheduler) .mutators(build_mutators!(mutator)) .observers(build_observers!(ResponseObserver::::new())) .processors(build_processors!(RequestProcessor::new(|_, _, _| {}))) .build(); } ``` -------------------------------- ### Implement ResponseProcessor usage Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/processors/struct.ResponseProcessor.html Example demonstrating how to create and use a ResponseProcessor to print response details after a request. ```rust // for testing, normal Response comes as a result of a sent request let reqwest_response = http::response::Builder::new().status(200).body("").unwrap(); let elapsed = Duration::from_secs(1); let response = BlockingResponse::try_from_reqwest_response(Request::default(), reqwest_response.into(), elapsed)?; // also not relevant to the current example, but it's needed to make the call to the hook let mut state = SharedState::with_corpus(RangeCorpus::with_stop(3).name("range").build()?); // a ResponseObserver should have already been created at some point let response_observer = ResponseObserver::with_response(response); let observers = build_observers!(response_observer); // create a ResponseProcessor that executes the provided closure after // the client has sent the request. Within the closure, // access to the fuzzer's instance of `ResponseObserver` is provided let mut response_printer = ResponseProcessor::new( |response_observer: &ResponseObserver, action, _state| { if let Some(action) = action { if matches!(action, Action::Keep) { println!( "[{}] {} - {} - {:?}", response_observer.status_code(), response_observer.content_length(), response_observer.url().to_string(), response_observer.elapsed() ); } } }, ); // finally, make the call to `post_send_hook`, allowing the side-effect to take place response_printer.post_send_hook(&mut state, &observers, None); ``` -------------------------------- ### Sending Requests with BlockingClient Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/client/struct.BlockingClient.html Example demonstrating how to initialize a BlockingClient with a custom reqwest client and send a request. ```rust use httpmock::prelude::*; let server = MockServer::start(); let mocked = server.mock(|when, then| { when.method(GET) .path("/doctest"); then.status(200); }); let mut request = Request::from_url(&server.url("/doctest"), None)?; // bring your own client let req_client = reqwest::blocking::Client::builder().build()?; let client = BlockingClient::with_client(req_client); let response = client.send(request)?; assert_eq!(mocked.hits(), 1); assert_eq!(response.status_code(), 200); ``` -------------------------------- ### Implement StatisticsProcessor usage Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/processors/struct.StatisticsProcessor.html Example demonstrating how to instantiate a StatisticsProcessor to print request statistics after a post-send hook. ```rust // for testing, normal Response comes as a result of a sent request let reqwest_response = http::response::Builder::new().status(200).body("").unwrap(); let elapsed = Duration::from_secs(1); let response = BlockingResponse::try_from_reqwest_response(Request::default(), reqwest_response.into(), elapsed)?; // also not relevant to the current example, but it's needed to make the call to the hook let mut state = SharedState::with_corpus(RangeCorpus::with_stop(3).name("range").build()?); // a ResponseObserver should have already been created at some point let response_observer = ResponseObserver::<_>::with_response(response); let observers = build_observers!(response_observer); // create a StatisticsProcessor that executes the provided closure after // the client has sent the request (aka `PostSend`). Within the closure, // access to the fuzzer's instance of `Statistics` is provided let mut stats_printer = StatisticsProcessor::new(Ordering::PostSend, |statistics, _action, _state| { if let Ok(guard) = statistics.read() { println!( "{} reqs/sec (requests: {}, elapsed: {:?})", guard.requests_per_sec(), guard.requests(), guard.elapsed() ); } }); // finally, make the call to `post_send_hook`, allowing the side-effect to take place stats_printer.post_send_hook(&mut state, &observers, None); ``` -------------------------------- ### RangeBuilder Configuration Methods Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/corpora/range.rs.html Methods for setting the start, stop, and step parameters of a RangeBuilder. ```rust impl RangeBuilder where IS: CorpusBuildState, NS: CorpusBuildState, { #[allow(clippy::missing_const_for_fn)] pub fn start(self, start: i64) -> Self { Self { start: Some(start), stop: self.stop, step: self.step, corpus_name: self.corpus_name, _item_state: PhantomData, _name_state: PhantomData, } } #[allow(clippy::missing_const_for_fn)] pub fn stop(self, stop: i64) -> RangeBuilder { RangeBuilder { start: self.start, stop: Some(stop), step: self.step, corpus_name: self.corpus_name, _item_state: PhantomData, _name_state: PhantomData, } } #[allow(clippy::missing_const_for_fn)] pub fn step(self, step: i64) -> Self { Self { start: self.start, stop: self.stop, step: Some(step), corpus_name: self.corpus_name, _item_state: PhantomData, _name_state: PhantomData, } } } ``` -------------------------------- ### Iterate over DirCorpus items Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/corpora/directory.rs.html Example usage of creating a DirCorpus from a directory and iterating over its contents. ```rust /// // create a Corpus of Strings from the given directory /// let mut corpus = DirCorpus::from_directory(tmp_dir.path())?.name("corpus").build(); /// /// let mut gathered = vec![]; /// /// for item in &corpus { /// gathered.push(item); /// } /// /// for item in expected { /// let data: Data = item.into(); /// assert!(gathered.contains(&&data)); /// } /// /// # Ok(()) /// # } ``` -------------------------------- ### Get Fuzzer Start Time Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/statistics/struct.Statistics.html Returns a reference to the fuzzer's recorded start time. ```rust pub const fn start_time(&self) -> &Duration> ``` -------------------------------- ### Initialize ProductScheduler Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/schedulers/struct.ProductScheduler.html Example demonstrating how to create a new ProductScheduler using two corpora and iterating through the resulting Cartesian product. ```rust use feroxfuzz::schedulers::{Scheduler, ProductScheduler}; use feroxfuzz::prelude::*; use feroxfuzz::corpora::{RangeCorpus, Wordlist}; // create two corpora, one with a set of user names, and one with a range of ids // where only even ids are considered let users = Wordlist::new().words(["user", "admin"]).name("users").build(); let ids = RangeCorpus::with_stop(5).name("ids").build()?; let state = SharedState::with_corpora([ids, users]); let order = ["users", "ids"]; let mut scheduler = ProductScheduler::new(order, state.clone())?; let mut counter = 0; while Scheduler::next(&mut scheduler).is_ok() { counter += 1; } // users.len() * ids.len() = 2 * 5 = 10 assert_eq!(counter, 10); ``` -------------------------------- ### Create HttpMethodsCorpus instances Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/corpora/struct.HttpMethodsCorpus.html Examples demonstrating how to initialize a corpus using all available methods or a specific subset of methods. ```rust // create a Corpus of all HTTP methods let corpus = HttpMethodsCorpus::all().name("corpus").build(); let expected = vec![ "GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE", "PATCH", ]; // resulting HttpMethodsCorpus has 9 entries assert_eq!(corpus.len(), 9); assert_eq!(corpus.items(), &expected); ``` ```rust // create a Corpus of all HTTP methods let corpus = HttpMethodsCorpus::new().method("GET").method("POST").name("corpus").build(); let expected = vec![ "GET", "POST", ]; // resulting HttpMethodsCorpus has 9 entries assert_eq!(corpus.len(), 2); assert_eq!(corpus.items(), &expected); ``` -------------------------------- ### Initialize Wordlist via new Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/corpora/struct.Wordlist.html Basic initialization using the new constructor followed by builder methods. ```rust let wordlist = Wordlist::new().word("1").name("smol").build(); ``` -------------------------------- ### Create and Use RequestRegexDecider Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/deciders/struct.RequestRegexDecider.html Example of creating a RequestRegexDecider with a regex and a comparator closure. The comparator determines whether to discard or keep a request based on its path matching the regex. Requires SharedState and Request setup. ```rust // not relevant to the current example, but needed to make the call to .post_send_hook let mut state = SharedState::with_corpus(RangeCorpus::with_stop(10).name("corpus").build()?); // our example Request, typically received from calling the Mutator hooks let request = Request::from_url("http://localhost:8000/ignore", None)?; // create a RequestRegexDecider with a regular expression and a closure // that will provide the 'how' of the decision making process. let decider = RequestRegexDecider::new("[iI]gnored?", |regex, request, _state| { match request.path().as_str() { Ok(path) => { if regex.is_match(path.as_bytes()) { Action::Discard } else { Action::Keep } } Err(_) => { Action::Discard } } }); ``` -------------------------------- ### Create a standard Wordlist Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/corpora/struct.Wordlist.html Demonstrates building a basic wordlist by chaining individual items and naming the list. ```rust let wordlist = Wordlist::new().word("1").word("2").name("words").build(); assert_eq!(wordlist.len(), 2); ``` -------------------------------- ### ResponseProcessor Example Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/processors/response.rs.html Demonstrates how to create and use a ResponseProcessor to print response details. It requires setting up a mock response, observers, and state. The processor's closure is executed in post_send_hook. ```rust use std::any::Any; use std::marker::PhantomData; use super::{Processor, ProcessorHooks}; use crate::actions::Action; use crate::metadata::AsAny; use crate::observers::{Observers, ResponseObserver}; use crate::responses::Response; use crate::state::SharedState; use crate::std_ext::tuple::Named; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use tracing::instrument; /// a `ResponseProcessor` provides access to the fuzzer's instance of [`ResponseObserver`] /// as well as the [`Action`] returned from calling the analogous hook on [`Deciders`]. /// /// Those two objects may be used to produce side-effects, such as printing, logging, /// etc... /// /// # Examples /// /// While the example below works, the normal use-case for this struct is to pass /// it, and any other [`Processors`] to the [`build_processors`] macro, and pass /// the result of that call to your chosen [`Fuzzer`] implementation. /// /// [`Fuzzer`]: crate::fuzzers::Fuzzer /// [`Deciders`]: crate::deciders::Deciders /// [`Processors`]: crate::processors::Processors /// [`build_processors`]: crate::build_processors /// /// ``` /// # use http::response; /// # use feroxfuzz::prelude::*; /// # use feroxfuzz::processors::{ResponseProcessor, ProcessorHooks}; /// # use feroxfuzz::observers::ResponseObserver; /// # use feroxfuzz::responses::BlockingResponse; /// # use feroxfuzz::corpora::RangeCorpus; /// # use feroxfuzz::requests::Request; /// # use feroxfuzz::actions::Action; /// # use std::time::Duration; /// # fn main() -> Result<(), FeroxFuzzError> { /// // for testing, normal Response comes as a result of a sent request /// let reqwest_response = http::response::Builder::new().status(200).body("").unwrap(); /// let elapsed = Duration::from_secs(1); /// let response = BlockingResponse::try_from_reqwest_response(Request::default(), reqwest_response.into(), elapsed)?; /// /// // also not relevant to the current example, but it's needed to make the call to the hook /// let mut state = SharedState::with_corpus(RangeCorpus::with_stop(3).name("range").build()?); /// /// // a ResponseObserver should have already been created at some point /// let response_observer = ResponseObserver::with_response(response); /// let observers = build_observers!(response_observer); /// /// // create a ResponseProcessor that executes the provided closure after /// // the client has sent the request. Within the closure, /// // access to the fuzzer's instance of `ResponseObserver` is provided /// let mut response_printer = ResponseProcessor::new( /// |response_observer: &ResponseObserver, action, _state| { /// if let Some(action) = action { /// if matches!(action, Action::Keep) { /// println!( /// "[{}] {} - {} - {:?}", /// response_observer.status_code(), /// response_observer.content_length(), /// response_observer.url().to_string(), /// response_observer.elapsed() /// ); /// } /// } /// }, /// ); /// /// // finally, make the call to `post_send_hook`, allowing the side-effect to take place /// response_printer.post_send_hook(&mut state, &observers, None); /// /// # Ok(()) /// # } /// ``` #[derive(Clone, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[allow(clippy::derive_partial_eq_without_eq)] // known false-positive introduced in 1.63.0 pub struct ResponseProcessor where R: Response, F: Fn(&ResponseObserver, Option<&Action>, &SharedState) + 'static, { processor: F, marker: PhantomData, } impl ResponseProcessor where F: Fn(&ResponseObserver, Option<&Action>, &SharedState) + 'static, R: Response, { /// create a new `ResponseProcessor` that calls `processor` in /// its `post_send_hook` method. Since `processor` receives a /// [`ResponseObserver`] as input, the implication is that it /// only makes sense to make `post_send_hook` available. pub const fn new(processor: F) -> Self { Self { processor, marker: PhantomData, } } } impl Processor for ResponseProcessor where F: Fn(&ResponseObserver, Option<&Action>, &SharedState) + Sync + Send + Clone + 'static, FnR: Response + Clone + Send + Sync + 'static, { } impl ProcessorHooks for ResponseProcessor where F: Fn(&ResponseObserver, Option<&Action>, &SharedState) + Sync + Send + Clone + 'static, FnR: Response + Clone + Send + Sync + 'static, { ``` -------------------------------- ### Manually Start Fuzzer Timer Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/statistics.rs.html Allows for manual adjustment of the fuzzer's start time, useful for pausing and resuming or when using `Statistics` independently. The `offset` is in seconds. ```rust pub fn start_timer(&mut self, offset: f64) { let adjustment = Duration::from_secs_f64(offset); self.start_time = current_time() .checked_sub(adjustment) .unwrap_or_else(|| Duration::from_secs_f64(0.0)); self.elapsed = self.elapsed(); } ``` -------------------------------- ### Get Current Time Since Unix Epoch Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/std_ext/time.rs.html Use this function to get the current system time as a Duration since the Unix epoch. It requires the `std::time` module. ```rust use std::time::{Duration, SystemTime, UNIX_EPOCH}; /// get current time since unix epoch #[must_use] #[inline] pub fn current_time() -> Duration { SystemTime::now().duration_since(UNIX_EPOCH).unwrap() } ``` -------------------------------- ### AsyncClient with_client Example Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/client/struct.AsyncClient.html Shows how to create an AsyncClient using a custom reqwest::Client with a specified timeout. This method may fail if a TLS backend cannot be initialized or the system resolver configuration cannot be loaded. ```rust use std::time::Duration; let req_client = reqwest::Client::builder().timeout(Duration::from_secs(7)).build()?; let client = AsyncClient::with_client(req_client); ``` -------------------------------- ### Initialize a DirCorpusBuilder Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/corpora/directory.rs.html Shows the setup for a DirCorpusBuilder, noting that build must be called after name and directory are set. ```rust # use feroxfuzz::corpora::DirCorpus; # use feroxfuzz::prelude::*; # use tempdir::TempDir; # use std::fs::File; # use std::io::Write; # fn main() -> Result<(), Box> { // test setup: // - 2 temporary directories that contain 1 file each // - each file has 2 lines ``` -------------------------------- ### Get Request ID Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/responses/async_response.rs.html Returns the RequestId for the response. ```rust fn id(&self) -> RequestId { self.request.id() } ``` -------------------------------- ### Generic Type - type_id Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/responses/struct.BlockingResponse.html Gets the TypeId of a generic type. ```APIDOC ## fn type_id(&self) -> TypeId ### Description Gets the `TypeId` of `self`. ### Method GET ### Endpoint /{type}/type_id ### Parameters #### Query Parameters - **self** (T) - Required - The generic type instance. ### Response #### Success Response (200) - **TypeId** (TypeId) - The TypeId of the instance. ``` -------------------------------- ### Create corpus with specific methods Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/corpora/struct.HttpMethodsCorpus.html Demonstrates initializing a corpus from an existing collection of methods. ```rust let methods_corpus = HttpMethodsCorpus::with_methods(["GET", "POST"]).name("methods").build(); ``` -------------------------------- ### Get Response Headers Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/responses/struct.BlockingResponse.html Retrieves a reference to the headers of the response. ```rust fn headers(&self) -> &HashMap> ``` -------------------------------- ### Iterate Over Wordlist Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/corpora/wordlist.rs.html Examples of non-consuming, mutable, and consuming iteration over a Wordlist. ```rust let expected = vec!["1", "2", "3"]; let wordlist = Wordlist::with_words(expected.clone()).name("words").build(); let mut gathered = vec![]; for i in &wordlist { gathered.push(i.clone()); } assert_eq!(gathered, expected); ``` ```rust let mut wordlist = Wordlist::new().words(["1", "2", "3"]).name("words").build(); for i in &mut wordlist { *i = "4".into(); } assert_eq!(wordlist.items(), &["4", "4", "4"]); ``` ```rust let expected = vec!["1", "2", "3"]; let wordlist = Wordlist::with_words(expected.clone()).name("words").build(); let mut gathered = vec![]; for i in wordlist { gathered.push(i.clone()); } assert_eq!(gathered, expected); ``` -------------------------------- ### Create and verify HttpMethodsCorpus instances Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/corpora/http_methods.rs.html Examples demonstrating how to initialize an HttpMethodsCorpus with all methods or a custom selection of methods using the builder pattern. ```rust # use feroxfuzz::corpora::HttpMethodsCorpus; # use feroxfuzz::prelude::*; # fn main() -> Result<(), Box> { // create a Corpus of all HTTP methods let corpus = HttpMethodsCorpus::all().name("corpus").build(); let expected = vec![ "GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE", "PATCH", ]; // resulting HttpMethodsCorpus has 9 entries assert_eq!(corpus.len(), 9); assert_eq!(corpus.items(), &expected); # Ok(()) # } ``` ```rust # use feroxfuzz::corpora::HttpMethodsCorpus; # use feroxfuzz::prelude::*; # fn main() -> Result<(), Box> { // create a Corpus of all HTTP methods let corpus = HttpMethodsCorpus::new().method("GET").method("POST").name("corpus").build(); let expected = vec![ "GET", "POST", ]; // resulting HttpMethodsCorpus has 9 entries assert_eq!(corpus.len(), 2); assert_eq!(corpus.items(), &expected); # Ok(()) # } ``` -------------------------------- ### Get Scheme Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/requests/request.rs.html Returns a reference to the scheme of the request, which is of type `Data`. ```rust /// get the scheme #[must_use] #[inline] pub const fn scheme(&self) -> &Data { &self.scheme } ``` -------------------------------- ### Get Response Body Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/responses/async_response.rs.html Returns a slice representing the body of the response. ```rust fn body(&self) -> &[u8] { self.body.as_ref() } ``` -------------------------------- ### Initialize Wordlist from file Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/corpora/struct.Wordlist.html Loads items from a file path into a wordlist. Empty lines and lines starting with '#' are typically ignored. ```rust let file_name = "smol-wordlist.txt"; let words = "one\ntwo\n\n\n#three\nfour\n"; fs::write(file_name, words); let wordlist = Wordlist::from_file(file_name)?.name("words").build(); fs::remove_file(file_name); assert_eq!(wordlist.len(), 3); assert_eq!(wordlist.items(), &["one", "two", "four"]); ``` -------------------------------- ### Create AsyncClient with reqwest Client Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/client/async_client.rs.html Demonstrates creating an AsyncClient by providing an existing reqwest::Client. This is useful when you need to configure the underlying reqwest client with specific options like timeouts. ```rust use reqwest; use std::time::Duration; use feroxfuzz::client::{AsyncClient, HttpClient}; use feroxfuzz::error::FeroxFuzzError; fn main() -> Result<(), FeroxFuzzError> { let req_client = reqwest::Client::builder().timeout(Duration::from_secs(7)).build()?; let client = AsyncClient::with_client(req_client); Ok(()) } ``` -------------------------------- ### Get Response Action Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/responses/struct.BlockingResponse.html Retrieves the action to be taken as a result of this response, if any. ```rust fn action(&self) -> Option<&Action> ``` -------------------------------- ### Get Response URL Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/responses/struct.BlockingResponse.html Retrieves a reference to the URL associated with this response. ```rust fn url(&self) -> &Url ``` -------------------------------- ### Create a RangeCorpus with default settings Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/corpora/range.rs.html Demonstrates initializing a RangeCorpus using the new() constructor and builder methods. ```rust # use feroxfuzz::corpora::RangeCorpus; # use feroxfuzz::prelude::*; # use tempdir::TempDir; # use std::fs::File; # use std::io::Write; # fn main() -> Result<(), Box> { let corpus = RangeCorpus::new().name("corpus").stop(10).build()?; assert_eq!(corpus.len(), 10); # Ok(()) # } ``` -------------------------------- ### AsyncClient Initialization Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/client/async_client.rs.html Initializes a new AsyncClient using a pre-configured reqwest::Client instance. ```APIDOC ## AsyncClient::with_client ### Description Creates a new AsyncClient instance using an existing reqwest::Client. ### Parameters - **client** (reqwest::Client) - Required - The underlying HTTP client to be used for requests. ### Request Example let req_client = reqwest::Client::builder().timeout(Duration::from_secs(7)).build()?; let client = AsyncClient::with_client(req_client); ``` -------------------------------- ### Get Mutable Headers Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/responses/struct.BlockingResponse.html Provides mutable access to the headers of the response. ```rust pub const fn headers_mut(&mut self) -> &mut HashMap> ``` -------------------------------- ### Usage example for ResponseRegexDecider Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/deciders/struct.ResponseRegexDecider.html Demonstrates how to instantiate a ResponseRegexDecider with a regex pattern and a closure to decide whether to keep or discard a response. ```rust // for testing; normally a Response comes as a result of a sent request let reqwest_response = http::response::Builder::new().status(200).body("XyZDeRpZyX").unwrap(); let elapsed = Duration::from_secs(1); let response = BlockingResponse::try_from_reqwest_response(Request::default(), reqwest_response.into(), elapsed)?; // not relevant to the current example, but needed to make the call to .post_send_hook let mut state = SharedState::with_corpus(RangeCorpus::with_stop(10).name("corpus").build()?); // our example Request, typically received from calling the Mutator hooks let request = Request::from_url("http://localhost:8000/ignore", None)?; // create a ResponseRegexDecider with a regular expression and a closure // that will provide the 'how' of the decision making process. Since // there are two different implementations of DeciderHooks, we need to provide type // information to the closure definition / compiler. let mut decider = ResponseRegexDecider::new("[dD][eE][rR][pP]", |regex, observer: &ResponseObserver, _state| { if regex.is_match(&observer.body()) { Action::Keep } else { Action::Discard } }); let observer = ResponseObserver::with_response(response); let observers = build_observers!(observer); // normally this is called from within a Fuzzer, not manually let action = decider.decide_with_observers(&mut state, &observers); assert_eq!(action, Some(Action::Keep)); ``` -------------------------------- ### Get RequestRegexDecider Name Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/deciders/struct.RequestRegexDecider.html Provides the static name of the RequestRegexDecider element. ```rust fn name(&self) -> &'static str ``` -------------------------------- ### Create a ResponseObserver with a response Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/observers/response.rs.html Demonstrates initializing a ResponseObserver using an existing response object. ```rust # use http; # use feroxfuzz::responses::{Response, AsyncResponse}; # use feroxfuzz::requests::Request; # use feroxfuzz::prelude::*; # use feroxfuzz::observers::ResponseObserver; # use tokio_test; # use std::time::Duration; # fn main() -> Result<(), FeroxFuzzError> { # tokio_test::block_on(async { // for testing, normal Response comes as a result of a sent request let reqwest_response = http::response::Builder::new().status(302).header("Location", "/somewhere").body("").unwrap(); // should come from timing during the client's send function let elapsed = Duration::from_secs(1); let response = AsyncResponse::try_from_reqwest_response(Request::default(), reqwest_response.into(), elapsed).await?; let observer = ResponseObserver::with_response(response); # Result::<(), FeroxFuzzError>::Ok(()) # }) # } ``` -------------------------------- ### Request Action Management Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/requests/request.rs.html Methods for getting and setting the action associated with a request. ```APIDOC ## GET /action ### Description Retrieves a reference to the fuzzer's decided action for this request, if any. ### Method GET ### Endpoint N/A (Method on struct) ### Parameters None ### Request Example ```rust # use feroxfuzz::requests::Request; # use feroxfuzz::actions::Action; # fn main() -> Result<(), Box> { let mut request = Request::new(); let action_ref = request.action(); # Ok(()) # } ``` ### Response #### Success Response (200) - **action** (*Option<&Action>*) - An optional reference to the `Action` enum. #### Response Example ```json { "action": "Discard" } ``` ``` ```APIDOC ## POST /set_action ### Description Updates the fuzzer's decided action for this request. ### Method POST ### Endpoint N/A (Method on struct) ### Parameters #### Request Body - **action** (*Option*) - Required - The new action to set for the request. ### Request Example ```rust # use feroxfuzz::requests::Request; # use feroxfuzz::actions::Action; # fn main() -> Result<(), Box> { let mut request = Request::new(); let new_action = Some(Action::Discard); request.set_action(new_action.clone()); assert_eq!(request.action(), new_action.as_ref()); # Ok(()) # } ``` ### Response #### Success Response (200) None (modifies the request in place) #### Response Example None ``` -------------------------------- ### Create a DirCorpus from a directory Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/corpora/directory.rs.html Demonstrates initializing a DirCorpus from a temporary directory containing files, where each line in the files is added as an entry. ```rust # use feroxfuzz::corpora::DirCorpus; # use feroxfuzz::corpora::Corpus; # use feroxfuzz::state::SharedState; # use feroxfuzz::Len; # use tempdir::TempDir; # use std::fs::File; # use std::io::Write; # fn main() -> Result<(), Box> { // test setup: // - temporary directory that contains 2 files // - each file has 2 lines let tmp_dir = TempDir::new("test-corpus")?; let file_one = tmp_dir.path().join("test-file-one"); let mut tmp_file = File::create(file_one)?; writeln!(tmp_file, "one")?; writeln!(tmp_file, "two")?; let file_two = tmp_dir.path().join("test-file-two"); tmp_file = File::create(file_two)?; writeln!(tmp_file, "three")?; writeln!(tmp_file, "four")?; // create a Corpus from the given directory let corpus = DirCorpus::from_directory(tmp_dir.path())?.name("corpus").build(); // resulting DirCorpus has 4 entries, one for each line found in the files above assert_eq!(corpus.len(), 4); # Ok(()) # } ``` -------------------------------- ### Get Request ID Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/requests/request.rs.html Returns the request ID. This is a constant time operation. ```rust /// get the id #[must_use] #[inline] pub const fn id(&self) -> RequestId { self.id } ``` -------------------------------- ### Create a WordlistBuilder with words Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/corpora/wordlist.rs.html Initializes a WordlistBuilder pre-populated with a collection of items. ```rust # use feroxfuzz::corpora::Wordlist; let wordlist = Wordlist::with_words(["1", "2", "3"]).name("words").build(); ``` -------------------------------- ### Get Associated Request Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/responses/mod.rs.html Returns a reference to the `Request` object from which this `Response` was generated. ```rust fn request(&self) -> &Request; ``` -------------------------------- ### Get Request Object Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/responses/async_response.rs.html Returns a reference to the Request object associated with the response. ```rust fn request(&self) -> &Request { &self.request } ``` -------------------------------- ### HttpMethodsCorpus Example Usage Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/corpora/http_methods.rs.html Demonstrates how to create and use an HttpMethodsCorpus, including setting a name and adding specific methods. ```APIDOC ## HttpMethodsCorpus Example Usage ### Description This example shows how to create a corpus of HTTP methods, name it, and then build the corpus. It also demonstrates how to verify the contents and size of the created corpus. ### Method Associated function (constructor) and builder pattern ### Endpoint N/A (This is a Rust struct method, not an API endpoint) ### Parameters None directly for the example, but builder methods like `name` and `build` are used. ### Request Example ```rust use feroxfuzz::corpora::HttpMethodsCorpus; use feroxfuzz::prelude::*; fn main() -> Result<(), Box> { // Create a Corpus of all HTTP methods and name it let corpus = HttpMethodsCorpus::all().name("all_methods_corpus").build(); let expected = vec![ "GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE", "PATCH", ]; // The resulting HttpMethodsCorpus should have 9 entries assert_eq!(corpus.len(), 9); assert_eq!(corpus.items(), &expected); // Example of creating a custom corpus let custom_corpus = HttpMethodsCorpus::new().method("GET").method("POST").name("custom_methods").build(); let custom_expected = vec!["GET", "POST"]; assert_eq!(custom_corpus.len(), 2); assert_eq!(custom_corpus.items(), &custom_expected); Ok(()) } ``` ### Response N/A (This is a code example, not an API response) ``` -------------------------------- ### Get Response Action Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/responses/async_response.rs.html Returns an optional reference to the Action associated with the response. ```rust fn action(&self) -> Option<&Action> { self.action.as_ref() } ``` -------------------------------- ### AsyncClient send Request Example Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/client/struct.AsyncClient.html Demonstrates how to send a request using an AsyncClient with a pre-built reqwest::Client. Ensure the httpmock crate is available for mocking HTTP servers. ```rust use httpmock::prelude::*; let server = MockServer::start(); let mocked = server.mock(|when, then| { when.method(GET) .path("/doctest"); then.status(200); }); let mut request = Request::from_url(&server.url("/doctest"), None)?; // bring your own client let req_client = reqwest::Client::builder().build()?; let client = AsyncClient::with_client(req_client); let response = client.send(request).await?; assert_eq!(mocked.hits(), 1); assert_eq!(response.status_code(), 200); ``` -------------------------------- ### Get Response Content Length Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/responses/async_response.rs.html Returns the length of the response body in bytes. ```rust fn content_length(&self) -> usize { self.content_length } ``` -------------------------------- ### Get Mutable Reference to Headers Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/responses/async_response.rs.html Provides a mutable reference to the headers of the response. ```rust pub const fn headers_mut(&mut self) -> &mut HashMap> { &mut self.headers } ``` -------------------------------- ### Create New Publisher Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/events/struct.Publisher.html Creates a new instance of the Publisher. ```rust pub fn new() -> Self ``` -------------------------------- ### Create DirCorpus from Directory (Builder Pattern) Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/corpora/directory.rs.html Demonstrates building a DirCorpus by adding directories. Requires calling .name() and .build() afterwards. Handles I/O errors during directory processing. ```rust /// let tmp_dir = TempDir::new("test-corpus-1").unwrap(); /// let tmp_dir2 = TempDir::new("test-corpus-2").unwrap(); /// /// let file_one = tmp_dir.path().join("test-file-one"); /// let mut tmp_file = File::create(file_one).unwrap(); /// writeln!(tmp_file, "one").unwrap(); /// writeln!(tmp_file, "two").unwrap(); /// /// let file_two = tmp_dir2.path().join("test-file-two"); /// tmp_file = File::create(file_two).unwrap(); /// writeln!(tmp_file, "three").unwrap(); /// writeln!(tmp_file, "four").unwrap(); /// /// let expected = vec!["one", "two", "three", "four"]; /// /// // create a Corpus of Strings from the given directory /// let corpus = DirCorpus::new() /// .directory(tmp_dir.path())? /// .directory(tmp_dir2.path())? /// .name("corpus") /// .build(); /// /// assert_eq!(corpus.items(), expected); /// # Ok(()) /// # } /// ``` ``` -------------------------------- ### Get Length of Inner Buffer Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/input.rs.html Returns the number of elements in the inner buffer. ```rust pub const fn len(&self) -> usize { match self { Self::Fuzzable(inner) | Self::Static(inner) => inner.len(), } } ``` -------------------------------- ### Get Request Timeouts Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/statistics/struct.Statistics.html Retrieves the count of request timeouts encountered by the fuzzer. ```rust pub const fn timeouts(&self) -> usize> ``` -------------------------------- ### Initialize Wordlist with collection Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/corpora/struct.Wordlist.html Initializes a wordlist builder using an existing collection of items. ```rust let wordlist = Wordlist::with_words(["1", "2", "3"]).name("words").build(); ``` -------------------------------- ### Get Request Method Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/responses/struct.BlockingResponse.html Retrieves the HTTP method of the request that generated this response. ```rust fn method(&self) -> &str ``` -------------------------------- ### Create a new WordlistBuilder Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/corpora/wordlist.rs.html Initializes a new empty WordlistBuilder instance. ```rust # use feroxfuzz::corpora::Wordlist; let wordlist = Wordlist::new().word("1").name("smol").build(); ``` -------------------------------- ### Get Response Status Code Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/responses/struct.BlockingResponse.html Retrieves the HTTP status code of the response. ```rust fn status_code(&self) -> u16 ``` -------------------------------- ### Test ProductScheduler with dynamic corpus updates Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/schedulers/product.rs.html Demonstrates initializing a ProductScheduler with multiple corpora and verifying iteration counts after adding new request fields. ```rust #[test] fn test_product_iterator_with_add_to_corpus_complex() { let outer = RangeCorpus::with_stop(2).name("outer").build().unwrap(); let first_middle = RangeCorpus::with_stop(1) .name("first_middle") .build() .unwrap(); let second_middle = RangeCorpus::with_stop(1) .name("second_middle") .build() .unwrap(); let inner = RangeCorpus::with_stop(1).name("inner").build().unwrap(); assert_eq!(outer.len(), 2); assert_eq!(first_middle.len(), 1); assert_eq!(second_middle.len(), 1); assert_eq!(inner.len(), 1); let state = SharedState::with_corpora([outer, first_middle, second_middle, inner]); let order = ["outer", "first_middle", "second_middle", "inner"]; let mut scheduler = ProductScheduler::new(order, state.clone()).unwrap(); let mut counter = 0; while Scheduler::next(&mut scheduler).is_ok() { counter += 1; } // 2 * 1 * 1 * 1 = 1 assert_eq!(counter, 2); // request with 2 fuzzable fields let request = Request::from_url( "http://localhost/admin", Some(&[ ShouldFuzz::RequestBody(b"administrator"), ShouldFuzz::URLPath, ]), ) .unwrap(); // when added to each corpus their legnth should increase by 2 for name in order { state.add_request_fields_to_corpus(name, &request).unwrap(); } assert_eq!(state.corpus_by_name("outer").unwrap().len(), 4); assert_eq!(state.corpus_by_name("first_middle").unwrap().len(), 3); assert_eq!(state.corpus_by_name("second_middle").unwrap().len(), 3); assert_eq!(state.corpus_by_name("inner").unwrap().len(), 3); scheduler.reset(); counter = 0; while Scheduler::next(&mut scheduler).is_ok() { counter += 1; } // 4 * 3 * 3 * 3 = 108 assert_eq!(counter, 108); } ``` -------------------------------- ### Wordlist Creation and Usage Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/corpora/wordlist.rs.html Demonstrates how to create a new Wordlist, add words to it, and build it. It also shows how to create a unique wordlist. ```APIDOC ## Wordlist Creation and Examples ### Description This section covers the creation and basic usage of the `Wordlist` struct in FeroxFuzz. It includes examples for creating a standard wordlist and a unique wordlist. ### Method N/A (Struct instantiation and builder pattern) ### Endpoint N/A ### Parameters N/A ### Request Example ```rust // Normal wordlist use feroxfuzz::corpora::Wordlist; let wordlist = Wordlist::new().word("1").word("2").name("words").build(); // Unique wordlist let unique_wordlist = Wordlist::new() .words(["one", "two", "three", "one", "two", "three"]) .name("unique_words") .unique() .build(); ``` ### Response N/A (This is client-side code) ### Response Example N/A ``` -------------------------------- ### Get Response ID Source: https://docs.rs/feroxfuzz/latest/feroxfuzz/responses/struct.BlockingResponse.html Retrieves the unique identifier of the request associated with this response. ```rust fn id(&self) -> RequestId ``` -------------------------------- ### Create and Iterate ProductScheduler Source: https://docs.rs/feroxfuzz/latest/src/feroxfuzz/schedulers/product.rs.html Demonstrates creating a ProductScheduler with two corpora (users and ids) and iterating through all possible combinations. Asserts that the total number of iterations matches the product of the corpus sizes. ```rust /// // create two corpora, one with a set of user names, and one with a range of ids /// // where only even ids are considered /// let users = Wordlist::new().words(["user", "admin"]).name("users").build(); /// let ids = RangeCorpus::with_stop(5).name("ids").build()?; /// /// let state = SharedState::with_corpora([ids, users]); /// /// let order = ["users", "ids"]; /// let mut scheduler = ProductScheduler::new(order, state.clone())?; /// /// let mut counter = 0; /// /// while Scheduler::next(&mut scheduler).is_ok() { /// counter += 1; /// } /// /// // users.len() * ids.len() = 2 * 5 = 10 /// assert_eq!(counter, 10); /// /// # Ok(()) /// # } ```