2024-08-06 22:28:38 +02:00
|
|
|
use mockito::{Matcher, Server, ServerOpts};
|
2023-03-02 20:05:18 +01:00
|
|
|
use nu_test_support::{nu, pipeline};
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn http_post_is_success() {
|
|
|
|
let mut server = Server::new();
|
|
|
|
|
|
|
|
let _mock = server.mock("POST", "/").match_body("foo").create();
|
|
|
|
|
|
|
|
let actual = nu!(pipeline(
|
|
|
|
format!(
|
|
|
|
r#"
|
|
|
|
http post {url} "foo"
|
|
|
|
"#,
|
|
|
|
url = server.url()
|
|
|
|
)
|
|
|
|
.as_str()
|
|
|
|
));
|
|
|
|
|
|
|
|
assert!(actual.out.is_empty())
|
|
|
|
}
|
2024-07-01 21:34:19 +02:00
|
|
|
#[test]
|
|
|
|
fn http_post_is_success_pipeline() {
|
|
|
|
let mut server = Server::new();
|
|
|
|
|
|
|
|
let _mock = server.mock("POST", "/").match_body("foo").create();
|
|
|
|
|
|
|
|
let actual = nu!(pipeline(
|
|
|
|
format!(
|
|
|
|
r#"
|
|
|
|
"foo" | http post {url}
|
|
|
|
"#,
|
|
|
|
url = server.url()
|
|
|
|
)
|
|
|
|
.as_str()
|
|
|
|
));
|
|
|
|
|
|
|
|
assert!(actual.out.is_empty())
|
|
|
|
}
|
2023-03-02 20:05:18 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn http_post_failed_due_to_server_error() {
|
|
|
|
let mut server = Server::new();
|
|
|
|
|
2023-03-05 23:48:13 +01:00
|
|
|
let _mock = server.mock("POST", "/").with_status(400).create();
|
2023-03-02 20:05:18 +01:00
|
|
|
|
|
|
|
let actual = nu!(pipeline(
|
|
|
|
format!(
|
|
|
|
r#"
|
|
|
|
http post {url} "body"
|
|
|
|
"#,
|
|
|
|
url = server.url()
|
|
|
|
)
|
|
|
|
.as_str()
|
|
|
|
));
|
|
|
|
|
|
|
|
assert!(actual.err.contains("Bad request (400)"))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn http_post_failed_due_to_missing_body() {
|
|
|
|
let mut server = Server::new();
|
|
|
|
|
|
|
|
let _mock = server.mock("POST", "/").create();
|
|
|
|
|
|
|
|
let actual = nu!(pipeline(
|
|
|
|
format!(
|
|
|
|
r#"
|
|
|
|
http post {url}
|
|
|
|
"#,
|
|
|
|
url = server.url()
|
|
|
|
)
|
|
|
|
.as_str()
|
|
|
|
));
|
|
|
|
|
2024-07-01 21:34:19 +02:00
|
|
|
assert!(actual
|
|
|
|
.err
|
|
|
|
.contains("Data must be provided either through pipeline or positional argument"))
|
2023-03-02 20:05:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn http_post_failed_due_to_unexpected_body() {
|
|
|
|
let mut server = Server::new();
|
|
|
|
|
|
|
|
let _mock = server.mock("POST", "/").match_body("foo").create();
|
|
|
|
|
|
|
|
let actual = nu!(pipeline(
|
|
|
|
format!(
|
|
|
|
r#"
|
|
|
|
http post {url} "bar"
|
|
|
|
"#,
|
|
|
|
url = server.url()
|
|
|
|
)
|
|
|
|
.as_str()
|
|
|
|
));
|
|
|
|
|
|
|
|
assert!(actual.err.contains("Cannot make request"))
|
|
|
|
}
|
2023-03-29 20:55:51 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn http_post_json_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())
|
|
|
|
}
|
2023-09-13 16:54:03 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn http_post_json_list_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())
|
|
|
|
}
|
Allow `http` commands' automatic redirect-following to be disabled (#11329)
Intends to close #8920
This PR suggests a new flag for the `http` commands, `--redirect-mode`,
which enables users to choose between different redirect handling modes.
The current behaviour of letting ureq silently follow redirects remains
the default, but two new options are introduced here, following the lead
of [JavaScript's `fetch`
API](https://developer.mozilla.org/en-US/docs/Web/API/fetch#redirect):
"manual", where any 3xx response to a request is simply returned as the
command's result, and "error", where any 3xx response causes a network
error like those caused by 4xx and 5xx responses.
This PR is a draft. Tests have not been added or run, the flag is
currently only implemented for the `http get` command, and design tweaks
are likely to be appropriate.
Most notably, it's not obvious to me whether a single flag which can
take one of three values is the nicest solution here.
We might instead consider two binary flags (like
`--no-following-redirects` and `--disallow-redirects`, although I'm bad
at naming things so I need help with that anyway), or completely drop
the "error" option if it's not deemed useful enough. (I personally think
it has some merit, especially since 4xx and 5xx responses are already
treated as errors by default; So this would allow users to treat only
immediate 2xx responses as success)
# User-facing changes
New options for the `http [method]` commands. Behaviour remains
unchanged when the command line flag introduced here is not used.
![image](https://github.com/nushell/nushell/assets/12228688/1eb89f14-7d48-4f41-8a3e-cc0f1bd0a4f8)
2023-12-28 08:26:34 +01:00
|
|
|
|
2024-09-04 23:05:39 +02:00
|
|
|
#[test]
|
|
|
|
fn http_post_json_int_is_success() {
|
|
|
|
let mut server = Server::new();
|
|
|
|
|
|
|
|
let mock = server.mock("POST", "/").match_body(r#"50"#).create();
|
|
|
|
|
|
|
|
let actual = nu!(format!(
|
|
|
|
r#"http post -t 'application/json' {url} 50"#,
|
|
|
|
url = server.url()
|
|
|
|
));
|
|
|
|
|
|
|
|
mock.assert();
|
|
|
|
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#""test""#).create();
|
|
|
|
|
|
|
|
let actual = nu!(format!(
|
|
|
|
r#"http post -t 'application/json' {url} "test""#,
|
|
|
|
url = server.url()
|
|
|
|
));
|
|
|
|
|
|
|
|
mock.assert();
|
|
|
|
assert!(actual.out.is_empty())
|
|
|
|
}
|
|
|
|
|
Allow `http` commands' automatic redirect-following to be disabled (#11329)
Intends to close #8920
This PR suggests a new flag for the `http` commands, `--redirect-mode`,
which enables users to choose between different redirect handling modes.
The current behaviour of letting ureq silently follow redirects remains
the default, but two new options are introduced here, following the lead
of [JavaScript's `fetch`
API](https://developer.mozilla.org/en-US/docs/Web/API/fetch#redirect):
"manual", where any 3xx response to a request is simply returned as the
command's result, and "error", where any 3xx response causes a network
error like those caused by 4xx and 5xx responses.
This PR is a draft. Tests have not been added or run, the flag is
currently only implemented for the `http get` command, and design tweaks
are likely to be appropriate.
Most notably, it's not obvious to me whether a single flag which can
take one of three values is the nicest solution here.
We might instead consider two binary flags (like
`--no-following-redirects` and `--disallow-redirects`, although I'm bad
at naming things so I need help with that anyway), or completely drop
the "error" option if it's not deemed useful enough. (I personally think
it has some merit, especially since 4xx and 5xx responses are already
treated as errors by default; So this would allow users to treat only
immediate 2xx responses as success)
# User-facing changes
New options for the `http [method]` commands. Behaviour remains
unchanged when the command line flag introduced here is not used.
![image](https://github.com/nushell/nushell/assets/12228688/1eb89f14-7d48-4f41-8a3e-cc0f1bd0a4f8)
2023-12-28 08:26:34 +01:00
|
|
|
#[test]
|
|
|
|
fn http_post_follows_redirect() {
|
|
|
|
let mut server = Server::new();
|
|
|
|
|
|
|
|
let _mock = server.mock("GET", "/bar").with_body("bar").create();
|
|
|
|
let _mock = server
|
|
|
|
.mock("POST", "/foo")
|
|
|
|
.with_status(301)
|
|
|
|
.with_header("Location", "/bar")
|
|
|
|
.create();
|
|
|
|
|
|
|
|
let actual = nu!(pipeline(
|
|
|
|
format!("http post {url}/foo postbody", url = server.url()).as_str()
|
|
|
|
));
|
|
|
|
|
|
|
|
assert_eq!(&actual.out, "bar");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn http_post_redirect_mode_manual() {
|
|
|
|
let mut server = Server::new();
|
|
|
|
|
|
|
|
let _mock = server
|
|
|
|
.mock("POST", "/foo")
|
|
|
|
.with_status(301)
|
|
|
|
.with_body("foo")
|
|
|
|
.with_header("Location", "/bar")
|
|
|
|
.create();
|
|
|
|
|
|
|
|
let actual = nu!(pipeline(
|
|
|
|
format!(
|
|
|
|
"http post --redirect-mode manual {url}/foo postbody",
|
|
|
|
url = server.url()
|
|
|
|
)
|
|
|
|
.as_str()
|
|
|
|
));
|
|
|
|
|
|
|
|
assert_eq!(&actual.out, "foo");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn http_post_redirect_mode_error() {
|
|
|
|
let mut server = Server::new();
|
|
|
|
|
|
|
|
let _mock = server
|
|
|
|
.mock("POST", "/foo")
|
|
|
|
.with_status(301)
|
|
|
|
.with_body("foo")
|
|
|
|
.with_header("Location", "/bar")
|
|
|
|
.create();
|
|
|
|
|
|
|
|
let actual = nu!(pipeline(
|
|
|
|
format!(
|
|
|
|
"http post --redirect-mode error {url}/foo postbody",
|
|
|
|
url = server.url()
|
|
|
|
)
|
|
|
|
.as_str()
|
|
|
|
));
|
|
|
|
|
|
|
|
assert!(&actual.err.contains("nu::shell::network_failure"));
|
|
|
|
assert!(&actual.err.contains(
|
|
|
|
"Redirect encountered when redirect handling mode was 'error' (301 Moved Permanently)"
|
|
|
|
));
|
|
|
|
}
|
2024-08-06 22:28:38 +02:00
|
|
|
#[test]
|
|
|
|
fn http_post_multipart_is_success() {
|
|
|
|
let mut server = Server::new_with_opts(ServerOpts {
|
|
|
|
assert_on_drop: true,
|
|
|
|
..Default::default()
|
|
|
|
});
|
|
|
|
let _mock = server
|
|
|
|
.mock("POST", "/")
|
|
|
|
.match_header(
|
|
|
|
"content-type",
|
|
|
|
Matcher::Regex("multipart/form-data; boundary=.*".to_string()),
|
|
|
|
)
|
|
|
|
.match_body(Matcher::AllOf(vec![
|
|
|
|
Matcher::Regex(r#"(?m)^Content-Disposition: form-data; name="foo""#.to_string()),
|
|
|
|
Matcher::Regex(r#"(?m)^Content-Type: application/octet-stream"#.to_string()),
|
|
|
|
Matcher::Regex(r#"(?m)^Content-Length: 3"#.to_string()),
|
|
|
|
Matcher::Regex(r#"(?m)^bar"#.to_string()),
|
|
|
|
]))
|
|
|
|
.with_status(200)
|
|
|
|
.create();
|
|
|
|
|
|
|
|
let actual = nu!(pipeline(
|
|
|
|
format!(
|
|
|
|
"http post --content-type multipart/form-data {url} {{foo: ('bar' | into binary) }}",
|
|
|
|
url = server.url()
|
|
|
|
)
|
|
|
|
.as_str()
|
|
|
|
));
|
|
|
|
|
|
|
|
assert!(actual.out.is_empty())
|
|
|
|
}
|