use crate::FeroxResult;
use console::{strip_ansi_codes, style, user_attended};
use indicatif::ProgressBar;
use reqwest::Url;
use reqwest::{Client, Response};
use std::convert::TryInto;
pub fn get_current_depth(target: &str) -> usize {
log::trace!("enter: get_current_depth({})", target);
let target = if !target.ends_with('/') {
format!("{}/", target)
} else {
String::from(target)
};
match Url::parse(&target) {
Ok(url) => {
if let Some(parts) = url.path_segments() {
let mut depth = 0;
for _ in parts {
depth += 1;
}
let return_val = depth;
log::trace!("exit: get_current_depth -> {}", return_val);
return return_val;
};
log::debug!(
"get_current_depth called on a Url that cannot be a base: {}",
url
);
log::trace!("exit: get_current_depth -> 0");
0
}
Err(e) => {
log::error!("could not parse to url: {}", e);
log::trace!("exit: get_current_depth -> 0");
0
}
}
}
pub fn status_colorizer(status: &str) -> String {
match status.chars().next() {
Some('1') => style(status).blue().to_string(),
Some('2') => style(status).green().to_string(),
Some('3') => style(status).yellow().to_string(),
Some('4') => style(status).red().to_string(),
Some('5') => style(status).red().to_string(),
Some('W') => style(status).cyan().to_string(),
Some('E') => style(status).red().to_string(),
_ => status.to_string(),
}
}
pub fn module_colorizer(modname: &str) -> String {
style(modname).cyan().to_string()
}
pub fn get_url_path_length(url: &Url) -> u64 {
log::trace!("enter: get_url_path_length({})", url);
let path = url.path();
let segments = if path.starts_with('/') {
path[1..].split_terminator('/')
} else {
log::trace!("exit: get_url_path_length -> 0");
return 0;
};
if let Some(last) = segments.last() {
let url_len: u64 = last
.len()
.try_into()
.expect("Failed usize -> u64 conversion");
log::trace!("exit: get_url_path_length -> {}", url_len);
return url_len;
}
log::trace!("exit: get_url_path_length -> 0");
0
}
pub fn ferox_print(msg: &str, bar: &ProgressBar) {
if user_attended() {
bar.println(msg);
} else {
let stripped = strip_ansi_codes(msg);
println!("{}", stripped);
}
}
pub fn format_url(
url: &str,
word: &str,
addslash: bool,
queries: &[(String, String)],
extension: Option<&str>,
) -> FeroxResult<Url> {
log::trace!(
"enter: format_url({}, {}, {}, {:?} {:?})",
url,
word,
addslash,
queries,
extension
);
let url = if !url.ends_with('/') {
format!("{}/", url)
} else {
url.to_string()
};
let base_url = reqwest::Url::parse(&url)?;
let word = if extension.is_some() {
format!("{}.{}", word, extension.unwrap())
} else if addslash && !word.ends_with('/') {
format!("{}/", word)
} else {
String::from(word)
};
match base_url.join(&word) {
Ok(request) => {
if queries.is_empty() {
log::trace!("exit: format_url -> {}", request);
Ok(request)
} else {
match reqwest::Url::parse_with_params(request.as_str(), queries) {
Ok(req_w_params) => {
log::trace!("exit: format_url -> {}", req_w_params);
Ok(req_w_params)
}
Err(e) => {
log::error!(
"Could not add query params {:?} to {}: {}",
queries,
request,
e
);
log::trace!("exit: format_url -> {}", request);
Ok(request)
}
}
}
}
Err(e) => {
log::trace!("exit: format_url -> {}", e);
log::error!("Could not join {} with {}", word, base_url);
Err(Box::new(e))
}
}
}
pub async fn make_request(client: &Client, url: &Url) -> FeroxResult<Response> {
log::trace!("enter: make_request(CONFIGURATION.Client, {})", url);
match client.get(url.to_owned()).send().await {
Ok(resp) => {
log::debug!("requested Url: {}", resp.url());
log::trace!("exit: make_request -> {:?}", resp);
Ok(resp)
}
Err(e) => {
log::trace!("exit: make_request -> {}", e);
if e.to_string().contains("operation timed out") {
log::warn!("Error while making request: {}", e);
} else {
log::error!("Error while making request: {}", e);
}
Err(Box::new(e))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn get_current_depth_base_url_returns_1() {
let depth = get_current_depth("http://localhost");
assert_eq!(depth, 1);
}
#[test]
fn get_current_depth_base_url_with_slash_returns_1() {
let depth = get_current_depth("http://localhost/");
assert_eq!(depth, 1);
}
#[test]
fn get_current_depth_one_dir_returns_2() {
let depth = get_current_depth("http://localhost/src");
assert_eq!(depth, 2);
}
#[test]
fn get_current_depth_one_dir_with_slash_returns_2() {
let depth = get_current_depth("http://localhost/src/");
assert_eq!(depth, 2);
}
#[test]
fn get_current_depth_single_forward_slash_is_zero() {
let depth = get_current_depth("");
assert_eq!(depth, 0);
}
#[test]
fn format_url_normal() {
assert_eq!(
format_url("http://localhost", "stuff", false, &Vec::new(), None).unwrap(),
reqwest::Url::parse("http://localhost/stuff").unwrap()
);
}
#[test]
fn format_url_no_word() {
assert_eq!(
format_url("http://localhost", "", false, &Vec::new(), None).unwrap(),
reqwest::Url::parse("http://localhost").unwrap()
);
}
#[test]
fn format_url_joins_queries() {
assert_eq!(
format_url(
"http://localhost",
"lazer",
false,
&[(String::from("stuff"), String::from("things"))],
None
)
.unwrap(),
reqwest::Url::parse("http://localhost/lazer?stuff=things").unwrap()
);
}
#[test]
fn format_url_without_word_joins_queries() {
assert_eq!(
format_url(
"http://localhost",
"",
false,
&[(String::from("stuff"), String::from("things"))],
None
)
.unwrap(),
reqwest::Url::parse("http://localhost/?stuff=things").unwrap()
);
}
#[test]
#[should_panic]
fn format_url_no_url() {
format_url("", "stuff", false, &Vec::new(), None).unwrap();
}
#[test]
fn format_url_word_with_preslash() {
assert_eq!(
format_url("http://localhost", "/stuff", false, &Vec::new(), None).unwrap(),
reqwest::Url::parse("http://localhost/stuff").unwrap()
);
}
#[test]
fn format_url_word_with_postslash() {
assert_eq!(
format_url("http://localhost", "stuff/", false, &Vec::new(), None).unwrap(),
reqwest::Url::parse("http://localhost/stuff/").unwrap()
);
}
#[test]
fn status_colorizer_uses_red_for_500s() {
assert_eq!(status_colorizer("500"), style("500").red().to_string());
}
#[test]
fn status_colorizer_uses_red_for_400s() {
assert_eq!(status_colorizer("400"), style("400").red().to_string());
}
#[test]
fn status_colorizer_uses_red_for_errors() {
assert_eq!(status_colorizer("ERROR"), style("ERROR").red().to_string());
}
#[test]
fn status_colorizer_uses_cyan_for_wildcards() {
assert_eq!(status_colorizer("WLD"), style("WLD").cyan().to_string());
}
#[test]
fn status_colorizer_uses_blue_for_100s() {
assert_eq!(status_colorizer("100"), style("100").blue().to_string());
}
#[test]
fn status_colorizer_uses_green_for_200s() {
assert_eq!(status_colorizer("200"), style("200").green().to_string());
}
#[test]
fn status_colorizer_uses_yellow_for_300s() {
assert_eq!(status_colorizer("300"), style("300").yellow().to_string());
}
#[test]
fn status_colorizer_returns_as_is() {
assert_eq!(status_colorizer("farfignewton"), "farfignewton".to_string());
}
}