From e12ba5be8f49fb06a1be182c8f940a54535b5ab3 Mon Sep 17 00:00:00 2001 From: Jonathan Rothberg Date: Sat, 28 Sep 2019 19:03:10 -0700 Subject: [PATCH 1/3] Added support for more `post` headers. --- src/commands/post.rs | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/commands/post.rs b/src/commands/post.rs index 1bff755d9e..ac41709eca 100644 --- a/src/commands/post.rs +++ b/src/commands/post.rs @@ -11,6 +11,11 @@ use std::path::PathBuf; use std::str::FromStr; use surf::mime; +pub enum HeaderKind { + ContentType(String), + ContentLength(String), +} + pub struct Post; impl PerItemCommand for Post { @@ -24,6 +29,8 @@ impl PerItemCommand for Post { .required("body", SyntaxShape::Any) .named("user", SyntaxShape::Any) .named("password", SyntaxShape::Any) + .named("content-type", SyntaxShape::Any) + .named("content-length", SyntaxShape::Any) .switch("raw") } @@ -73,9 +80,30 @@ fn run( let registry = registry.clone(); let raw_args = raw_args.clone(); + let content_type = call_info + .args + .get("content-type") + .map(|x| x.as_string().unwrap()); + + let content_length = call_info + .args + .get("content-length") + .map(|x| x.as_string().unwrap()); + + let mut headers = vec![]; + match content_type { + Some(ct) => headers.push(HeaderKind::ContentType(ct)), + None => {} + }; + + match content_length { + Some(cl) => headers.push(HeaderKind::ContentLength(cl)), + None => {} + }; + let stream = async_stream! { let (file_extension, contents, contents_tag, span_source) = - post(&path_str, &body, user, password, path_span, ®istry, &raw_args).await.unwrap(); + post(&path_str, &body, user, password, &headers, path_span, ®istry, &raw_args).await.unwrap(); let file_extension = if has_raw { None @@ -143,6 +171,7 @@ pub async fn post( body: &Tagged, user: Option, password: Option, + headers: &Vec, tag: Tag, registry: &CommandRegistry, raw_args: &RawCommandArgs, @@ -164,6 +193,13 @@ pub async fn post( if let Some(login) = login { s = s.set_header("Authorization", format!("Basic {}", login)); } + + for h in headers { + s = match h { + HeaderKind::ContentType(ct) => s.set_header("Content-Type", ct), + HeaderKind::ContentLength(cl) => s.set_header("Content-Length", cl), + }; + } s.await } Tagged { From e1357a9541952f29243a3f1c1f1000d6fcdecbc8 Mon Sep 17 00:00:00 2001 From: Jonathan Rothberg Date: Sun, 29 Sep 2019 01:29:43 -0700 Subject: [PATCH 2/3] Handle unexpected input and some cleanup. --- src/commands/post.rs | 67 +++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/src/commands/post.rs b/src/commands/post.rs index ac41709eca..db1a084f12 100644 --- a/src/commands/post.rs +++ b/src/commands/post.rs @@ -80,26 +80,7 @@ fn run( let registry = registry.clone(); let raw_args = raw_args.clone(); - let content_type = call_info - .args - .get("content-type") - .map(|x| x.as_string().unwrap()); - - let content_length = call_info - .args - .get("content-length") - .map(|x| x.as_string().unwrap()); - - let mut headers = vec![]; - match content_type { - Some(ct) => headers.push(HeaderKind::ContentType(ct)), - None => {} - }; - - match content_length { - Some(cl) => headers.push(HeaderKind::ContentLength(cl)), - None => {} - }; + let headers = get_headers(&call_info)?; let stream = async_stream! { let (file_extension, contents, contents_tag, span_source) = @@ -166,6 +147,52 @@ fn run( Ok(stream.to_output_stream()) } +fn get_headers(call_info: &CallInfo) -> Result, ShellError> { + let mut headers = vec![]; + + match extract_header_value(&call_info, "content-type") { + Ok(h) => match h { + Some(ct) => headers.push(HeaderKind::ContentType(ct)), + None => {} + }, + Err(e) => { + return Err(e); + } + }; + + match extract_header_value(&call_info, "content-length") { + Ok(h) => match h { + Some(cl) => headers.push(HeaderKind::ContentLength(cl)), + None => {} + }, + Err(e) => { + return Err(e); + } + }; + + Ok(headers) +} + +fn extract_header_value(call_info: &CallInfo, key: &str) -> Result, ShellError> { + if call_info.args.has(key) { + let val = match call_info.args.get(key) { + Some(Tagged { + item: Value::Primitive(Primitive::String(s)), + .. + }) => s.clone(), + _ => { + return Err(ShellError::string(format!( + "{} not in expected format. Expected string.", + key + ))); + } + }; + return Ok(Some(val)); + } + + Ok(None) +} + pub async fn post( location: &str, body: &Tagged, From 83d82a09b21bbf09e9be84aa292e2f626a697526 Mon Sep 17 00:00:00 2001 From: Jonathan Rothberg Date: Sun, 29 Sep 2019 14:43:39 -0700 Subject: [PATCH 3/3] Better handling of unexpected error case. --- src/commands/post.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/commands/post.rs b/src/commands/post.rs index 9d08bd3a3a..5a77afd14b 100644 --- a/src/commands/post.rs +++ b/src/commands/post.rs @@ -175,16 +175,25 @@ fn get_headers(call_info: &CallInfo) -> Result, ShellError> { fn extract_header_value(call_info: &CallInfo, key: &str) -> Result, ShellError> { if call_info.args.has(key) { - let val = match call_info.args.get(key) { + let tagged = call_info.args.get(key); + let val = match tagged { Some(Tagged { item: Value::Primitive(Primitive::String(s)), .. }) => s.clone(), + Some(Tagged { tag, .. }) => { + return Err(ShellError::labeled_error( + format!("{} not in expected format. Expected string.", key), + "post error", + tag, + )); + } _ => { - return Err(ShellError::string(format!( - "{} not in expected format. Expected string.", - key - ))); + return Err(ShellError::labeled_error( + format!("{} not in expected format. Expected string.", key), + "post error", + Tag::unknown(), + )); } }; return Ok(Some(val));