I'm brand new to using rust, so please bear with me. I'm trying to write a rust program which takes two arguments: A URL, and a wordlist. This wordlist has the following contents, and is several hundred thousand lines long:
...
example1.php
example2.php
example3.php
...
I want to read all of these from the wordlist file, then as quickly as possible (asychronously??) send a head request to the URL + the filename in the wordlist (for example if we do rust_fuzzer https://example.com examplewordlist.com, it should send the requests to https://example.com/example1.php...) then check if the status code is a 200. If it is, add it to a string vec, then at the end of the program print the vec using "{:?}" formatter.
So far, I have the following code, which seems to work much faster than the python equivalent I wrote (I'm much more familiar with python), however I do wonder if it could go faster, and if I've done the async stuff right. The code is sort of hacked together from existing stuff I found online and my own (very basic) understanding of the language. I would really appreciate some improvement suggestions (apart from the obvious like error handling which I'll figure out after the main part is done).
use std::fs::File;
use std::io::{self, BufRead};
use std::path::Path;
use std::env;
use reqwest::Client;
use reqwest::Url;
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where P: AsRef<Path>, {
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}
async fn fuzzer(url_string: &String, file_path: &String) -> Vec<String>{
let Ok(base_url) = Url::parse(url_string) else { todo!() };
let mut found_resources = Vec::new();
let client = Client::new();
if let Ok(lines) = read_lines(file_path) {
for line in lines {
if let Ok(resource) = line {
let Ok(target_url) = base_url.join(&resource) else { todo!() };
let response = client.head(target_url.as_str()).send().await;
if !response.is_err() {
if response.unwrap().status() == reqwest::StatusCode::OK {
found_resources.push(resource);
}
}
}
}
}
else { println!("Something went wrong reading the file.."); }
return found_resources;
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>>{
let args: Vec<String> = env::args().collect();
if args.len() == 3 {
let found_resources = fuzzer(&args[1], &args[2]).await;
println!("{:?}", found_resources);
}
else {
println!("USAGE: ./rust_fuzzer <URL> <Wordlist>");
}
Ok(())
}
Essentially, I want this code to get the status codes and add the resources with a 200 code to the String Vec as fast as possible, but I know I may have to consider rate limiting and whatnot