diff options
author | Guillaume Pasquet <dev@etenil.net> | 2022-03-28 03:38:07 +0000 |
---|---|---|
committer | Guillaume Pasquet <dev@etenil.net> | 2022-03-28 03:38:07 +0000 |
commit | 6fda3e33ebeb27485a9259f2d07c0507871f58a9 (patch) | |
tree | 755005f90be61268326cf97a68571c2a1131693a | |
parent | e18c7e97b2bde449be234de25b657909acaf10c7 (diff) |
Set headers from the command line
-rw-r--r-- | .gitlab-ci.yml | 10 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | src/barbfile.rs | 37 | ||||
-rw-r--r-- | src/executor.rs | 96 | ||||
-rw-r--r-- | src/main.rs | 52 | ||||
-rw-r--r-- | src/output.rs | 39 |
6 files changed, 182 insertions, 54 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f1a229f..019530a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,10 +7,16 @@ variables: CARGO_INCREMENTAL: 0 test: + variables: + JQ_LIB_DIR: /usr/lib/x86_64-linux-gnu stage: test - script: + before_script: - apt update && apt install libjq1 libjq-dev libonig-dev libonig5 - - JQ_LIB_DIR=/usr/lib/x86_64-linux-gnu cargo test --all --verbose + - rustup component add rustfmt + script: + - cargo fmt -- --check + - cargo build --tests + - cargo test --all # pretty: # stage: test @@ -59,6 +59,8 @@ barb [options] <file 1> <file 2> ... <file n> - `-V, --version`: Print the software version - `-n, --no-color`: Don't use color output - `-f, --filter`: A JSON path to override any filters defined in the barb file +- `-F, --no-filter`: Disable all filters (except for dependencies) +- `--hdr <HDR>`: Set/override a header with format `NAME=VALUE`, can appear multiple times (does not affect dependencies) - `--help`: Displays the help page ## Barb format diff --git a/src/barbfile.rs b/src/barbfile.rs index 54ee031..e5ef916 100644 --- a/src/barbfile.rs +++ b/src/barbfile.rs @@ -1,13 +1,12 @@ use jsonpath_rust::JsonPathQuery; use regex::Regex; use serde_json::Value; +use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use std::fs; +use std::path::Path; use std::str::FromStr; use std::string::ToString; use std::{error::Error, fmt}; -use std::cmp::{Eq, PartialEq, PartialOrd, Ord, Ordering}; -use std::fs; -use std::path::Path; - #[cfg(feature = "jq")] use jq_rs; @@ -210,7 +209,13 @@ struct BarbPreamble { } impl BarbPreamble { - fn new(method: Method, url: String, headers: Vec<Header>, filters: Vec<BarbFilter>, dependency: Option<String>) -> Self { + fn new( + method: Method, + url: String, + headers: Vec<Header>, + filters: Vec<BarbFilter>, + dependency: Option<String>, + ) -> Self { BarbPreamble { method, url, @@ -257,7 +262,9 @@ impl BarbFile { let dep_path = Path::new(dep); if !dep_path.is_absolute() { - let my_path = Path::new(&self.file_name).parent().or(Some(Path::new("")))?; + let my_path = Path::new(&self.file_name) + .parent() + .or(Some(Path::new("")))?; return Some(String::from(my_path.join(dep_path).to_str()?)); } @@ -307,8 +314,9 @@ impl BarbFile { let mut bfile = Self::from_str( fs::read_to_string(file_name.as_str()) .map_err(|_| BarbParseError {})? - .as_str() - ).map_err(|_| BarbParseError {})?; + .as_str(), + ) + .map_err(|_| BarbParseError {})?; bfile.file_name = file_name; Ok(bfile) } @@ -479,12 +487,19 @@ mod tests { #[test] fn test_parse_dependency() { let bfile = BarbFile::from_str("#GET^http://test.com\n#>blah.barb").unwrap(); - assert_eq!(bfile.dependency().as_ref().unwrap(), &String::from("blah.barb")); + assert_eq!( + bfile.dependency().as_ref().unwrap(), + &String::from("blah.barb") + ); } #[test] fn test_parse_mult_dependency_keeps_last() { - let bfile = BarbFile::from_str("#GET^http://test.com\n#>blah.barb\n#>foo.barb\n#>bar.barb").unwrap(); - assert_eq!(bfile.dependency().as_ref().unwrap(), &String::from("bar.barb")); + let bfile = BarbFile::from_str("#GET^http://test.com\n#>blah.barb\n#>foo.barb\n#>bar.barb") + .unwrap(); + assert_eq!( + bfile.dependency().as_ref().unwrap(), + &String::from("bar.barb") + ); } } diff --git a/src/executor.rs b/src/executor.rs index 4323bc0..6b1bc5a 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -42,14 +42,15 @@ impl Context { let value = String::from( var.name("value") .map(|m| m.as_str()) - .or(Some(&String::from(""))).unwrap() + .or(Some(&String::from(""))) + .unwrap(), ); buffer = buffer.replace( // Since this iterates over matches, having match 0 is guaranteed. So the // `unwrap()` operation here is safe. var.get(0).unwrap().as_str(), - self.vars.get(&key).or(Some(&value)).unwrap() + self.vars.get(&key).or(Some(&value)).unwrap(), ); } @@ -66,23 +67,32 @@ impl Executor { Executor { context } } - fn make_req(&self, bfile: &BarbFile, output: &BarbOutput) -> ureq::Request { - output.req( - bfile.method_as_string(), - self.context.substitute(&bfile.url()), - ); + fn make_req( + &self, + bfile: &BarbFile, + headers: Vec<(String, String)>, + output: &BarbOutput, + ) -> ureq::Request { let mut req = ureq::request( bfile.method_as_string().as_str(), self.context.substitute(&bfile.url()).as_str(), ); + let mut final_headers: HashMap<String, String> = HashMap::new(); + for header in bfile.headers() { let hdr_val = self.context.substitute(header.value()); - req = req.set(header.name(), hdr_val.as_str()); - output.req_hdr(header.name().to_string(), hdr_val); + final_headers.insert(String::from(header.name()), hdr_val); } - output.end_req(); + for header in headers { + final_headers.insert(header.0, header.1); + } + + for (hdr_name, hdr_val) in final_headers.iter() { + req = req.set(hdr_name.as_str(), hdr_val.as_str()); + output.req_hdr(String::from(hdr_name), String::from(hdr_val)); + } req } @@ -125,15 +135,34 @@ impl Executor { } } + pub fn execute_dep(&mut self, bfile: &BarbFile, output: &BarbOutput) -> Result<(), String> { + let req = self.make_req(&bfile, vec![], output); + let method = String::from(req.method()); + let url = String::from(req.url()); + + let response = self.run(&bfile, req)?; + + output.req_dep(method, url, response.status(), response.status_text()); + output.end_req(); + self.apply_filters(&bfile, response.into_string().unwrap(), &None)?; + + Ok(()) + } + pub fn execute( &mut self, bfile: &BarbFile, output: &BarbOutput, filter: &Option<String>, - skip_filters: bool + skip_filters: bool, + headers: Vec<(String, String)>, ) -> Result<(), String> { - let response = self.run(&bfile, self.make_req(&bfile, output))?; - //let response = executor.execute(&bfile, &output)?; + let req = self.make_req(&bfile, headers, output); + + output.req(String::from(req.method()), String::from(req.url())); + output.end_req(); + + let response = self.run(&bfile, req)?; output.status(response.status(), response.status_text()); for header_name in response.headers_names() { @@ -144,7 +173,7 @@ impl Executor { } output.end_resp_hdr(); - if ! skip_filters { + if !skip_filters { output.body(self.apply_filters(&bfile, response.into_string().unwrap(), filter)?); } else { output.body(response.into_string().unwrap()); @@ -217,9 +246,7 @@ mod tests_context { #[test] fn test_context_substitute_value_with_default() { - let vars: Vec<(String, String)> = vec![ - (String::from("chewie"), String::from("han")), - ]; + let vars: Vec<(String, String)> = vec![(String::from("chewie"), String::from("han"))]; let ctx = Context::new(vars.into_iter()); assert_eq!( ctx.substitute(&String::from("blah blah {chewie:-wookie} blah")), @@ -247,8 +274,8 @@ mod tests_make_req { fn test_make_req_simple_get() { let executor = Executor::new(Context::empty()); let bfile = BarbFile::from_str("#GET^http://foo.bar\n\n").unwrap(); - let output = BarbOutput::new(false, false, false, false, false, false); - let req = executor.make_req(&bfile, &output); + let output = BarbOutput::quiet(); + let req = executor.make_req(&bfile, vec![], &output); assert_eq!(req.url(), "http://foo.bar"); assert_eq!(req.method(), "GET"); @@ -258,14 +285,33 @@ mod tests_make_req { fn test_make_req_simple_headers() { let executor = Executor::new(Context::empty()); let bfile = BarbFile::from_str("#GET^http://foo.bar\n#Foo: Bar\n#Bar: Baz\n\n").unwrap(); - let output = BarbOutput::new(false, false, false, false, false, false); - let req = executor.make_req(&bfile, &output); + let output = BarbOutput::quiet(); + let req = executor.make_req(&bfile, vec![], &output); - assert_eq!( - req.header_names(), - vec![String::from("foo"), String::from("bar")] - ); + let mut header_names = req.header_names(); + header_names.sort(); + + assert_eq!(header_names, vec![String::from("bar"), String::from("foo")]); assert_eq!(req.header("foo"), Some("Bar")); assert_eq!(req.header("bar"), Some("Baz")); } + + #[test] + fn test_make_req_headers_override() { + let executor = Executor::new(Context::empty()); + let bfile = BarbFile::from_str("#GET^http://foo.bar\n#Foo: Bar\n#Bar: Baz\n\n").unwrap(); + let output = BarbOutput::quiet(); + let req = executor.make_req( + &bfile, + vec![(String::from("Foo"), String::from("Qux"))], + &output, + ); + + let mut header_names = req.header_names(); + header_names.sort(); + + assert_eq!(header_names, vec![String::from("bar"), String::from("foo")]); + assert_eq!(req.header("foo"), Some("Qux")); + assert_eq!(req.header("bar"), Some("Baz")); + } } diff --git a/src/main.rs b/src/main.rs index 151b277..6ebfc45 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,6 +26,8 @@ struct Args { no_color: bool, #[clap(short = 'F', long)] no_filter: bool, + #[clap(long)] + hdr: Vec<String>, files: Vec<String>, } @@ -42,6 +44,18 @@ impl Args { self.no_filter } + pub fn hdrs(&self) -> Vec<(String, String)> { + self.hdr + .iter() + .map(|x| x.split_once('=')) + .filter(|x| x.is_some()) + .map(|x| { + let (def, val) = x.unwrap(); + (String::from(def), String::from(val)) + }) + .collect::<Vec<(String, String)>>() + } + pub fn output(&self) -> BarbOutput { BarbOutput::new( !self.body, @@ -65,32 +79,32 @@ fn main() { let mut executor = Executor::new(Context::new(env::vars())); let output = args.output(); - let files: Vec<Result<BarbFile, String>> = args.files_iter() - .map(read_file_barb) - .collect(); + let files: Vec<Result<BarbFile, String>> = args.files_iter().map(read_file_barb).collect(); - let (maybe_deps, errors): (Vec<Result<BarbFile, String>>, Vec<Result<BarbFile, String>>) = files.iter() - .map(|x| match x.as_ref().ok() { - Some(bfile) => bfile.dependency(), - None => None - }) - .filter(|x| x.is_some()) - .map(|x| read_file_barb(&String::from(x.unwrap()))) - .partition(|x| x.is_ok()); + let (maybe_deps, errors): (Vec<Result<BarbFile, String>>, Vec<Result<BarbFile, String>>) = + files + .iter() + .map(|x| match x.as_ref().ok() { + Some(bfile) => bfile.dependency(), + None => None, + }) + .filter(|x| x.is_some()) + .map(|x| read_file_barb(&String::from(x.unwrap()))) + .partition(|x| x.is_ok()); for e in errors { println!("{}", e.err().unwrap()); } - let mut dependencies = maybe_deps.iter() + let mut dependencies = maybe_deps + .iter() .map(|x| x.as_ref().unwrap()) .collect::<Vec<&BarbFile>>(); dependencies.sort(); dependencies.dedup(); for dep in dependencies { - // Always enable filters on dependencies - match executor.execute(&dep, &output, args.jq_filter(), false) { + match executor.execute_dep(&dep, &output) { Ok(()) => (), Err(err) => println!("{}", err), } @@ -101,8 +115,14 @@ fn main() { println!("{}", e); continue; } - - match executor.execute(&bfile.unwrap(), &output, args.jq_filter(), args.no_filter()) { + + match executor.execute( + &bfile.unwrap(), + &output, + args.jq_filter(), + args.no_filter(), + args.hdrs(), + ) { Ok(()) => (), Err(err) => println!("{}", err), } diff --git a/src/output.rs b/src/output.rs index d7ab74e..0f0e4a9 100644 --- a/src/output.rs +++ b/src/output.rs @@ -39,6 +39,45 @@ impl BarbOutput { } } + #[cfg(test)] + pub fn quiet() -> BarbOutput { + BarbOutput { + request: false, + req_headers: false, + headers: false, + body: false, + raw_body: false, + color: false, + } + } + + pub fn req_dep(&self, method: String, url: String, code: u16, text: &str) { + if !self.request { + return; + } + if self.color { + if code >= 400 { + println!( + "{} {} {} {}", + code.to_string().red(), + text.red(), + method.red(), + url.red() + ); + } else { + println!( + "{} {} {} {}", + code.to_string().green(), + text, + method.purple(), + url.purple() + ); + } + } else { + println!("{} {} {} {}", code, text, method, url); + } + } + pub fn req(&self, method: String, url: String) { if !self.request { return; |