String values should pass their content-type correctly on http requests with a body (e.g. http post) (#13731)

# Description
The content-type was not being handled appropriately when sending
requests with a string value.

# User-Facing Changes
- Passing a string value through a pipeline with a content-type set as
metadata is handled correctly
- Passing a string value as a parameter with a content-type set as a
flag is handled correctly.
This commit is contained in:
Jack Wright 2024-09-05 16:29:50 -07:00 committed by GitHub
parent d0c2adabf7
commit 2d360fda7f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 48 additions and 16 deletions

View file

@ -7,6 +7,7 @@ use base64::{
use multipart_rs::MultipartWriter;
use nu_engine::command_prelude::*;
use nu_protocol::{ByteStream, LabeledError, Signals};
use serde_json::Value as JsonValue;
use std::{
collections::HashMap,
io::Cursor,
@ -257,24 +258,37 @@ fn send_json_request(
span: Span,
signals: &Signals,
) -> Result<Response, ShellErrorOrRequestError> {
let data = match body {
match body {
Value::Int { .. } | Value::List { .. } | Value::Record { .. } => {
value_to_json_value(&body)?
let data = value_to_json_value(&body)?;
send_cancellable_request(request_url, Box::new(|| req.send_json(data)), span, signals)
}
// If the body type is string, assume it is string json content.
// If parsing fails, just send the raw string
Value::String { val: s, .. } => {
serde_json::from_str(&s).unwrap_or_else(|_| nu_json::Value::String(s))
if let Ok(jvalue) = serde_json::from_str::<JsonValue>(&s) {
send_cancellable_request(
request_url,
Box::new(|| req.send_json(jvalue)),
span,
signals,
)
} else {
let data = serde_json::from_str(&s).unwrap_or_else(|_| nu_json::Value::String(s));
send_cancellable_request(
request_url,
Box::new(|| req.send_json(data)),
span,
signals,
)
}
}
_ => {
return Err(ShellErrorOrRequestError::ShellError(
ShellError::UnsupportedHttpBody {
msg: format!("Accepted types: [Int, List, String, Record]. Check: {HTTP_DOCS}"),
},
))
}
};
send_cancellable_request(request_url, Box::new(|| req.send_json(data)), span, signals)
_ => Err(ShellErrorOrRequestError::ShellError(
ShellError::UnsupportedHttpBody {
msg: format!("Accepted types: [Int, List, String, Record]. Check: {HTTP_DOCS}"),
},
)),
}
}
fn send_form_request(

View file

@ -126,7 +126,7 @@ impl Command for SubCommand {
},
Example {
description: "Patch JSON content from a pipeline to example.com",
example: "open foo.json | http patch https://www.example.com",
example: "open --raw foo.json | http patch https://www.example.com",
result: None,
},
]

View file

@ -124,7 +124,7 @@ impl Command for SubCommand {
},
Example {
description: "Post JSON content from a pipeline to example.com",
example: "open foo.json | http post https://www.example.com",
example: "open --raw foo.json | http post https://www.example.com",
result: None,
},
Example {

View file

@ -124,7 +124,7 @@ impl Command for SubCommand {
},
Example {
description: "Put JSON content from a pipeline to example.com",
example: "open foo.json | http put https://www.example.com",
example: "open --raw foo.json | http put https://www.example.com",
result: None,
},
]

View file

@ -115,6 +115,24 @@ fn http_post_json_is_success() {
assert!(actual.out.is_empty())
}
#[test]
fn http_post_json_string_is_success() {
let mut server = Server::new();
let mock = server
.mock("POST", "/")
.match_body(r#"{"foo":"bar"}"#)
.create();
let actual = nu!(format!(
r#"http post -t 'application/json' {url} '{{"foo":"bar"}}'"#,
url = server.url()
));
mock.assert();
assert!(actual.out.is_empty())
}
#[test]
fn http_post_json_list_is_success() {
let mut server = Server::new();
@ -149,7 +167,7 @@ fn http_post_json_int_is_success() {
}
#[test]
fn http_post_json_string_is_success() {
fn http_post_json_raw_string_is_success() {
let mut server = Server::new();
let mock = server.mock("POST", "/").match_body(r#""test""#).create();