Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit

Permalink
-o option added
Browse files Browse the repository at this point in the history
  • Loading branch information
gabriel-schneider-vtex committed Apr 2, 2023
1 parent 466e73a commit e5e3a26
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 79 deletions.
60 changes: 60 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ xmltree = "0.10"
itertools = "0.10.5"
anyhow = "1.0.70"
thiserror = "1.0"
threadpool = "1.8"
threadpool = "1.8"
snailquote = "0.3"
strip-ansi-escapes = "0.1"
58 changes: 19 additions & 39 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
pub mod print;
mod tests;

use anyhow::{Context, Result};
use clap::{Arg, Parser, ValueEnum};
use clap::{Parser, ValueEnum};
use colored::Colorize;
use itertools::Itertools;
use reqwest::{
Expand Down Expand Up @@ -35,49 +36,26 @@ pub struct CliArgs {
/// URL or file with URLs to send the request
url_or_file: String,

#[arg(short = 'c', long)]
status_code: bool,

#[arg(short, long)]
size: bool,

/// Validate the data as xml or json
#[arg(long)]
validate: bool,

#[arg(short = 't', long)]
content_type: bool,

#[arg(short, long)]
no_body: bool,

/// Try to guess the JSON's format
#[arg(short, long)]
keys: bool,

/// Display the URL
#[arg(short = 'u', long)]
show_url: bool,

/// Number of parallel threads to send the requests
#[arg(short = 'p', default_value = "4")]
nworkers: usize,

/// Display all status
#[arg(long)]
all: bool,

#[arg(long)]
scripts: Vec<String>,

#[arg(short = 'X', default_value = "GET")]
verb: Verb,

#[arg(short = 'b', long = "body")]
show_response_body: bool,

/// Data to be sent in the request body
#[arg(short, long)]
data: Option<String>,

#[arg(long)]
verbose: bool,
#[arg(long, default_value = "0")]
verbosity_level: usize,

/// File to write the results
#[arg(short)]
output: Option<String>,
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -147,7 +125,7 @@ fn urls(args: &CliArgs) -> Vec<String> {
}

/// This is a blocking function that will only return when all the requests
fn execute_requests(args: &CliArgs) {
fn execute_requests(args: &CliArgs) -> Result<()> {
let params = urls(&args)
.into_iter()
.map(|url| RequestParam {
Expand All @@ -173,20 +151,22 @@ fn execute_requests(args: &CliArgs) {
//eprintln!("started {}", rp.url);
match request(rp) {
Ok(response) => {
print::log_response(&args, response, &url).unwrap();
tx.send(1).unwrap();
let res = print::log_response(&args, response, &url);
tx.send(res.unwrap_or("".to_owned())).unwrap();
}

// TODO: Log error when in verbose mode
Err(_) => tx.send(0).unwrap(),
Err(_) => tx.send("".to_owned()).unwrap(),
}
});
}

// TODO tif some request panics, this will halt the application
// TODO: if some request panics, this will halt the application
let res = rx.into_iter().take(n).collect_vec();
// verbose
//eprintln!("{res:?}");

print::write_results(args, res)
}

fn main() -> Result<()> {
Expand Down
103 changes: 64 additions & 39 deletions src/print.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use strip_ansi_escapes::strip;

use crate::*;

#[derive(Clone, Debug, PartialEq)]
Expand Down Expand Up @@ -58,7 +60,7 @@ fn get_xml_keys(xml: &xmltree::Element) -> Vec<String> {
}
}

pub fn log_response(args: &CliArgs, resp: Response, url: &str) -> Result<()> {
pub fn log_response(args: &CliArgs, resp: Response, url: &str) -> Result<String> {
let headers = resp.headers().clone();

let status = resp.status();
Expand All @@ -85,32 +87,31 @@ pub fn log_response(args: &CliArgs, resp: Response, url: &str) -> Result<()> {
let data_fmt = get_format(&data.as_ref().unwrap());

let mut buf = vec![];

if args.status_code || args.all {
if status.is_success() {
buf.push(format!("{}", status.as_u16()).green())
} else if status.is_server_error() {
buf.push(format!("{}", status.as_u16()).red())
} else if status.is_client_error() {
buf.push(format!("{}", status.as_u16()).yellow())
} else {
buf.push(format!("{}", status.as_u16()).black())
}
let mut ret_str = String::new();

// status_code
if status.is_success() {
buf.push(format!("{}", status.as_u16()).green());
} else if status.is_server_error() {
buf.push(format!("{}", status.as_u16()).red())
} else if status.is_client_error() {
buf.push(format!("{}", status.as_u16()).yellow())
} else {
buf.push(format!("{}", status.as_u16()).black())
}

if args.size || args.all {
buf.push(format!("{}", len).normal());
}
// response size
buf.push(format!("{}", len).normal());

if args.all {
match args.verb {
Verb::GET => buf.push("get".green()),
Verb::POST => buf.push("post".blue()),
Verb::HEAD => buf.push("head".yellow()),
}
// http verb
match args.verb {
Verb::GET => buf.push("get".green()),
Verb::POST => buf.push("post".blue()),
Verb::HEAD => buf.push("head".yellow()),
}

if args.validate || args.all {
// data format
{
use DataFormat::*;
match &data_fmt {
Some(Json(_)) => buf.push("json".green().bold()),
Expand All @@ -119,7 +120,8 @@ pub fn log_response(args: &CliArgs, resp: Response, url: &str) -> Result<()> {
}
}

if data_fmt.is_some() && (args.keys || args.all) {
// show keys from json or xml
if data_fmt.is_some() {
use DataFormat::*;
let keys = match data_fmt.unwrap() {
Json(json) => get_json_keys(&json),
Expand All @@ -128,15 +130,13 @@ pub fn log_response(args: &CliArgs, resp: Response, url: &str) -> Result<()> {
buf.push(format!("\"{}\"", keys.join(" ")).white().bold());
}

if args.content_type || args.all {
buf.push(format!("\"{}\"", content_type).normal());
}
// content-type
buf.push(format!("\"{}\"", content_type).normal());

if args.show_url || args.all {
buf.push(format!("{}", url).normal());
}
// url
buf.push(format!("{}", url).normal());

if !args.no_body {
if args.show_response_body {
buf.push(
format!(
"{}{}",
Expand All @@ -149,15 +149,40 @@ pub fn log_response(args: &CliArgs, resp: Response, url: &str) -> Result<()> {

//TODO: implement header printing

if !buf.is_empty() {
println!(
"{}",
buf.into_iter()
.map(|x| format!("{}", x))
.collect::<Vec<_>>()
.join(" ")
);
let final_string = buf
.into_iter()
.map(|x| format!("{}", x))
.collect_vec()
.join(" ");

if !final_string.is_empty() {
println!("{}", final_string);
}

Ok(())
let no_colors =
strip(final_string.as_bytes()).context("while removing ansi symbols from string")?;
let no_colors = std::str::from_utf8(&no_colors).context("while decoding str to utf-8")?;
//snailquote::unescape(no_colors).context("while unescaping string")
Ok(no_colors.to_owned())
}

pub fn write_results(args: &CliArgs, data: Vec<String>) -> Result<()> {
if args.output.is_none() {
return Ok(());
}

let fname = args.output.clone().unwrap();

let s = data
.into_iter()
.filter(|s| !s.is_empty())
.sorted_by_key(|s| {
let len: String = s.split_ascii_whitespace().skip(1).take(1).collect();
let n: usize = len.parse().unwrap();
// -n for inverse
1i64 - (n as i64)
})
.join("\n");

std::fs::write(fname, format!("{}\n", s)).context("while writing to file")
}
7 changes: 7 additions & 0 deletions src/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#[cfg(test)]
mod tests {
use crate::*;

#[test]
fn a() {}
}
Loading

0 comments on commit e5e3a26

Please sign in to comment.