1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use anyhow::{bail, Result};
use clap::Parser;
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub struct Args {
/// The name of a request file to execute and exit.
/// Omit this argument to run an interactive prompt.
pub name: Option<String>,
/// Optional Name=Value pairs to substitute in the request.
/// These will override values in the config file.
#[arg(value_parser = parse_key_val)]
pub options: Vec<(String, String)>,
/// When running interactively (no name argument specified),
/// repeat asking for requests until cancelled.
#[arg(short, long)]
pub repeat: bool,
/// Select a target from the config file
#[arg(
short,
long,
conflicts_with = "name",
conflicts_with = "repeat",
conflicts_with = "flurry",
conflicts_with = "watch",
)]
pub select: Option<Option<String>>,
/// Target to run a request against
#[arg(short, long)]
pub target: Option<String>,
/// Show more output
#[arg(short, long)]
pub verbose: bool,
/// Show no output except the returned data
#[arg(short, long)]
pub quiet: bool,
/// Skip SSL certificate validation
#[arg(short('k'), long)]
pub insecure: bool,
/// Do not ask questions
#[arg(short, long, requires = "name")]
pub non_interactive: bool,
/// Flurry attack an API by sending many identical requests in a short
/// time.
#[arg(short, long, conflicts_with = "repeat", requires = "name")]
pub flurry: Option<i32>,
/// Repeat the same request indefinely, with the given number of seconds
/// delay between hits.
#[arg(
short,
long,
conflicts_with = "repeat",
conflicts_with = "flurry",
conflicts_with = "watch",
requires = "name"
)]
pub monitor: Option<i32>,
/// Number concurrent connections used in a flurry attack.
#[arg(short, long, requires = "flurry")]
pub connections: Option<i32>,
/// Watch file for changes (implies non-interactove).
#[arg(short, long, requires = "name", conflicts_with = "flurry")]
pub watch: bool,
}
/// Parse a single key-value pair
fn parse_key_val(s: &str) -> Result<(String, String)> {
match s.find('=') {
Some(0) => bail!("empty key in `{s}`"),
Some(pos) => {
Ok((s[..pos].trim().to_string(), s[pos + 1..].trim().to_string()))
}
None => bail!("no `=` found in `{s}`"),
}
}
pub fn parse_args() -> Args {
Args::parse()
}