From f6ca62384e6140c32894ba94a3d703c7b08ae67f Mon Sep 17 00:00:00 2001 From: Filip Andersson Date: Sun, 5 Mar 2023 23:48:13 +0100 Subject: [PATCH] changes Reqwest to Ureq. (#8320) # Description _(Thank you for improving Nushell. Please, check our [contributing guide](../CONTRIBUTING.md) and talk to the core team before making major changes.)_ This pull request removes `Reqwest` and replaces it with `Ureq` to remove some of our dependencies, giving us faster compile times as well as smaller binaries. `Ureq` does not have an async runtime included so we do not need build heavy dependencies such as `Tokio`. From older tests I had the number of build units be reduced from `430 -> 392`. The default of `Ureq` uses `Rustls` but it has been configured to instead use `native_tls` which should work exactly the same as the `tls` works now. I removed `content-length` from the http commands as after refactoring i did not see a reason to have it available, correct me if this is something we should preserve. In the medium, to long term, we should maybe consider changing to `rustls` to have the same `tls` on all platforms. # User-Facing Changes _(List of all changes that impact the user experience here. This helps us keep track of breaking changes.)_ # Tests + Formatting Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass # After Submitting If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date. --- Cargo.lock | 116 +++------- crates/nu-command/Cargo.toml | 3 +- crates/nu-command/src/network/http/client.rs | 219 +++++++++--------- crates/nu-command/src/network/http/delete.rs | 20 +- crates/nu-command/src/network/http/get.rs | 19 +- crates/nu-command/src/network/http/head.rs | 10 +- crates/nu-command/src/network/http/patch.rs | 17 +- crates/nu-command/src/network/http/post.rs | 17 +- crates/nu-command/src/network/http/put.rs | 17 +- .../tests/commands/network/http/delete.rs | 6 +- .../tests/commands/network/http/get.rs | 6 +- .../tests/commands/network/http/head.rs | 6 +- .../tests/commands/network/http/patch.rs | 6 +- .../tests/commands/network/http/post.rs | 6 +- .../tests/commands/network/http/put.rs | 6 +- 15 files changed, 172 insertions(+), 302 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 60c133fff9..52f9016dda 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1805,19 +1805,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - [[package]] name = "iana-time-zone" version = "0.1.50" @@ -1934,12 +1921,6 @@ dependencies = [ "windows-sys 0.45.0", ] -[[package]] -name = "ipnet" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" - [[package]] name = "is-root" version = "0.1.2" @@ -2496,9 +2477,9 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" dependencies = [ "lazy_static", "libc", @@ -2773,6 +2754,7 @@ dependencies = [ "mime", "mime_guess", "mockito", + "native-tls", "notify", "nu-ansi-term", "nu-cmd-lang", @@ -2808,7 +2790,6 @@ dependencies = [ "rayon", "reedline", "regex", - "reqwest", "roxmltree", "rstest", "rusqlite", @@ -2829,13 +2810,14 @@ dependencies = [ "umask", "unicode-segmentation", "unicode-width", + "ureq", "url", "users 0.11.0", "uuid", "wax", "which", "windows", - "winreg 0.11.0", + "winreg", ] [[package]] @@ -4309,43 +4291,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "reqwest" -version = "0.11.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "431949c384f4e2ae07605ccaa56d1d9d2ecdb5cadd4f9577ccfab29f2e5149fc" -dependencies = [ - "base64 0.13.0", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-native-tls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg 0.10.1", -] - [[package]] name = "retain_mut" version = "0.1.9" @@ -4583,12 +4528,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" dependencies = [ - "lazy_static", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] [[package]] @@ -4614,9 +4558,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.7.0" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" dependencies = [ "bitflags", "core-foundation", @@ -4627,9 +4571,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.6.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" dependencies = [ "core-foundation-sys", "libc", @@ -5389,16 +5333,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.4" @@ -5629,6 +5563,23 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1e5fa573d8ac5f1a856f8d7be41d390ee973daf97c806b2c1a465e4e1406e68" +[[package]] +name = "ureq" +version = "2.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "338b31dd1314f68f3aabf3ed57ab922df95ffcd902476ca7ba3c4ce7b908c46d" +dependencies = [ + "base64 0.13.0", + "encoding_rs", + "flate2", + "log", + "native-tls", + "once_cell", + "serde", + "serde_json", + "url", +] + [[package]] name = "url" version = "2.3.1" @@ -6085,15 +6036,6 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" -[[package]] -name = "winreg" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" -dependencies = [ - "winapi", -] - [[package]] name = "winreg" version = "0.11.0" diff --git a/crates/nu-command/Cargo.toml b/crates/nu-command/Cargo.toml index b70fb2d2ee..a8765e38d4 100644 --- a/crates/nu-command/Cargo.toml +++ b/crates/nu-command/Cargo.toml @@ -72,7 +72,8 @@ quick-xml = "0.27" rand = "0.8" rayon = "1.6.1" regex = "1.7.1" -reqwest = { version = "0.11", features = ["blocking", "json"] } +ureq = { version = "2.6.2", default-features = false, features = ["json", "charset", "native-tls", "gzip"] } +native-tls = "0.2.11" roxmltree = "0.18.0" rust-embed = "6.3.0" same-file = "1.0.6" diff --git a/crates/nu-command/src/network/http/client.rs b/crates/nu-command/src/network/http/client.rs index 1847e56985..b67be6b4fc 100644 --- a/crates/nu-command/src/network/http/client.rs +++ b/crates/nu-command/src/network/http/client.rs @@ -7,8 +7,8 @@ use nu_protocol::engine::{EngineState, Stack}; use nu_protocol::{ BufferedReader, IntoPipelineData, PipelineData, RawStream, ShellError, Span, Value, }; -use reqwest::blocking::{RequestBuilder, Response}; -use reqwest::{blocking, Error, StatusCode}; +use ureq::{Error, ErrorKind, Request, Response}; + use std::collections::HashMap; use std::io::BufReader; use std::path::PathBuf; @@ -25,12 +25,16 @@ pub enum BodyType { // Only panics if the user agent is invalid but we define it statically so either // it always or never fails -pub fn http_client(allow_insecure: bool) -> blocking::Client { - blocking::Client::builder() - .user_agent("nushell") +pub fn http_client(allow_insecure: bool) -> ureq::Agent { + let tls = native_tls::TlsConnector::builder() .danger_accept_invalid_certs(allow_insecure) .build() - .expect("Failed to build reqwest client") + .expect("Failed to build network tls"); + + ureq::builder() + .user_agent("nushell") + .tls_connector(std::sync::Arc::new(tls)) + .build() } pub fn http_parse_url( @@ -62,15 +66,9 @@ pub fn response_to_buffer( ) -> PipelineData { // Try to get the size of the file to be downloaded. // This is helpful to show the progress of the stream. - let buffer_size = match &response.headers().get("content-length") { + let buffer_size = match response.header("content-length") { Some(content_length) => { - let content_length = &(*content_length).clone(); // binding - - let content_length = content_length - .to_str() - .unwrap_or("") - .parse::() - .unwrap_or(0); + let content_length = content_length.parse::().unwrap_or_default(); if content_length == 0 { None @@ -81,7 +79,8 @@ pub fn response_to_buffer( _ => None, }; - let buffered_input = BufReader::new(response); + let reader = response.into_reader(); + let buffered_input = BufReader::new(reader); PipelineData::ExternalStream { stdout: Some(RawStream::new( @@ -103,8 +102,8 @@ pub fn response_to_buffer( pub fn request_add_authorization_header( user: Option, password: Option, - mut request: RequestBuilder, -) -> RequestBuilder { + mut request: Request, +) -> Request { let base64_engine = GeneralPurpose::new(&alphabet::STANDARD, PAD); let login = match (user, password) { @@ -127,71 +126,87 @@ pub fn request_add_authorization_header( }; if let Some(login) = login { - request = request.header("Authorization", format!("Basic {login}")); + request = request.set("Authorization", &format!("Basic {login}")); } request } -pub fn request_set_body( +pub fn send_request( + request: Request, + span: Span, + body: Option, content_type: Option, - content_length: Option, - body: Value, - mut request: RequestBuilder, -) -> Result { - // set the content-type header before using e.g., request.json - // because that will avoid duplicating the header value - if let Some(val) = &content_type { - request = request.header("Content-Type", val); +) -> Result { + let request_url = request.url().to_string(); + if body.is_none() { + return request + .call() + .map_err(|err| handle_response_error(span, &request_url, err)); } + let body = body.expect("Should never be none."); let body_type = match content_type { Some(it) if it == "application/json" => BodyType::Json, Some(it) if it == "application/x-www-form-urlencoded" => BodyType::Form, _ => BodyType::Unknown, }; - match body { - Value::Binary { val, .. } => { - request = request.body(val); - } - Value::String { val, .. } => { - request = request.body(val); - } + Value::Binary { val, .. } => request + .send_bytes(&val) + .map_err(|err| handle_response_error(span, &request_url, err)), + Value::String { val, .. } => request + .send_string(&val) + .map_err(|err| handle_response_error(span, &request_url, err)), Value::Record { .. } if body_type == BodyType::Json => { let data = value_to_json_value(&body)?; - request = request.json(&data); + request + .send_json(data) + .map_err(|err| handle_response_error(span, &request_url, err)) } - Value::Record { .. } if body_type == BodyType::Form => { - let data = value_to_json_value(&body)?; - request = request.form(&data); + Value::Record { cols, vals, .. } if body_type == BodyType::Form => { + let mut data: Vec<(String, String)> = Vec::with_capacity(cols.len()); + + for (col, val) in cols.iter().zip(vals.iter()) { + data.push((col.clone(), val.as_string()?)) + } + + let data = data + .iter() + .map(|(a, b)| (a.as_str(), b.as_str())) + .collect::>(); + + request + .send_form(&data[..]) + .map_err(|err| handle_response_error(span, &request_url, err)) } Value::List { vals, .. } if body_type == BodyType::Form => { if vals.len() % 2 != 0 { return Err(ShellError::IOError("unsupported body input".into())); } + let data = vals .chunks(2) .map(|it| Ok((it[0].as_string()?, it[1].as_string()?))) .collect::, ShellError>>()?; - request = request.form(&data) - } - _ => { - return Err(ShellError::IOError("unsupported body input".into())); - } - }; - if let Some(val) = content_length { - request = request.header("Content-Length", val); + let data = data + .iter() + .map(|(a, b)| (a.as_str(), b.as_str())) + .collect::>(); + + request + .send_form(&data) + .map_err(|err| handle_response_error(span, &request_url, err)) + } + _ => Err(ShellError::IOError("unsupported body input".into())), } - - Ok(request) } pub fn request_set_timeout( timeout: Option, - mut request: RequestBuilder, -) -> Result { + mut request: Request, +) -> Result { if let Some(timeout) = timeout { let val = timeout.as_i64()?; if val.is_negative() || val < 1 { @@ -210,8 +225,8 @@ pub fn request_set_timeout( pub fn request_add_custom_headers( headers: Option, - mut request: RequestBuilder, -) -> Result { + mut request: Request, +) -> Result { if let Some(headers) = headers { let mut custom_headers: HashMap = HashMap::new(); @@ -257,7 +272,7 @@ pub fn request_add_custom_headers( for (k, v) in &custom_headers { if let Ok(s) = v.as_string() { - request = request.header(k, s); + request = request.set(k, &s); } } } @@ -265,48 +280,41 @@ pub fn request_add_custom_headers( Ok(request) } -fn handle_response_error(span: Span, requested_url: &String, response: Error) -> ShellError { - // Explicitly turn 4xx and 5xx statuses into errors. - if response.is_timeout() { - ShellError::NetworkFailure(format!("Request to {requested_url} has timed out"), span) - } else if response.is_status() { - match response.status() { - Some(err_code) if err_code == StatusCode::NOT_FOUND => ShellError::NetworkFailure( - format!("Requested file not found (404): {requested_url:?}"), - span, - ), - Some(err_code) if err_code == StatusCode::MOVED_PERMANENTLY => { - ShellError::NetworkFailure( - format!("Resource moved permanently (301): {requested_url:?}"), - span, - ) - } - Some(err_code) if err_code == StatusCode::BAD_REQUEST => { - ShellError::NetworkFailure(format!("Bad request (400) to {requested_url:?}"), span) - } - - Some(err_code) if err_code == StatusCode::FORBIDDEN => ShellError::NetworkFailure( - format!("Access forbidden (403) to {requested_url:?}"), - span, - ), - _ => ShellError::NetworkFailure( - format!( - "Cannot make request to {:?}. Error is {:?}", - requested_url, - response.to_string() - ), - span, - ), +fn handle_response_error(span: Span, requested_url: &str, response_err: Error) -> ShellError { + match response_err { + Error::Status(301, _) => ShellError::NetworkFailure( + format!("Resource moved permanently (301): {requested_url:?}"), + span, + ), + Error::Status(400, _) => { + ShellError::NetworkFailure(format!("Bad request (400) to {requested_url:?}"), span) } - } else { - ShellError::NetworkFailure( + Error::Status(403, _) => { + ShellError::NetworkFailure(format!("Access forbidden (403) to {requested_url:?}"), span) + } + Error::Status(404, _) => ShellError::NetworkFailure( + format!("Requested file not found (404): {requested_url:?}"), + span, + ), + Error::Status(408, _) => { + ShellError::NetworkFailure(format!("Request timeout (408): {requested_url:?}"), span) + } + Error::Status(_, _) => ShellError::NetworkFailure( format!( "Cannot make request to {:?}. Error is {:?}", requested_url, - response.to_string() + response_err.to_string() ), span, - ) + ), + + Error::Transport(t) => match t { + t if t.kind() == ErrorKind::ConnectionFailed => ShellError::NetworkFailure( + format!("Cannot make request to {requested_url}, there was an error establishing a connection.",), + span, + ), + t => ShellError::NetworkFailure(t.to_string(), span), + }, } } @@ -316,20 +324,11 @@ pub fn request_handle_response( span: Span, requested_url: &String, raw: bool, - response: Result, + response: Result, ) -> Result { match response { - Ok(resp) => match resp.headers().get("content-type") { + Ok(resp) => match resp.header("content-type") { Some(content_type) => { - let content_type = content_type.to_str().map_err(|e| { - ShellError::GenericError( - e.to_string(), - "".to_string(), - None, - Some("MIME type were invalid".to_string()), - Vec::new(), - ) - })?; let content_type = mime::Mime::from_str(content_type).map_err(|_| { ShellError::GenericError( format!("MIME type unknown: {content_type}"), @@ -386,29 +385,29 @@ pub fn request_handle_response( } None => Ok(response_to_buffer(resp, engine_state, span)), }, - Err(e) => Err(handle_response_error(span, requested_url, e)), + Err(e) => Err(e), } } pub fn request_handle_response_headers( span: Span, - requested_url: &String, - response: Result, + response: Result, ) -> Result { match response { Ok(resp) => { - let cols: Vec = resp.headers().keys().map(|name| name.to_string()).collect(); + let cols = resp.headers_names(); let mut vals = Vec::with_capacity(cols.len()); - for value in resp.headers().values() { - match value.to_str() { - Ok(str_value) => vals.push(Value::String { + for key in &cols { + match resp.header(key) { + // match value.to_str() { + Some(str_value) => vals.push(Value::String { val: str_value.to_string(), span, }), - Err(err) => { + None => { return Err(ShellError::GenericError( - format!("Failure when converting header value: {err}"), + "Failure when converting header value".to_string(), "".to_string(), None, Some("Failure when converting header value".to_string()), @@ -420,6 +419,6 @@ pub fn request_handle_response_headers( Ok(Value::Record { cols, vals, span }.into_pipeline_data()) } - Err(e) => Err(handle_response_error(span, requested_url, e)), + Err(e) => Err(e), } } diff --git a/crates/nu-command/src/network/http/delete.rs b/crates/nu-command/src/network/http/delete.rs index 9cf0fa34e7..530de68cc0 100644 --- a/crates/nu-command/src/network/http/delete.rs +++ b/crates/nu-command/src/network/http/delete.rs @@ -7,7 +7,7 @@ use nu_protocol::{ use crate::network::http::client::{ http_client, http_parse_url, request_add_authorization_header, request_add_custom_headers, - request_handle_response, request_set_body, request_set_timeout, + request_handle_response, request_set_timeout, send_request, }; #[derive(Clone)] @@ -46,12 +46,6 @@ impl Command for SubCommand { "the MIME type of content to post", Some('t'), ) - .named( - "content-length", - SyntaxShape::Any, - "the length of the content being posted", - Some('l'), - ) .named( "max-time", SyntaxShape::Int, @@ -137,7 +131,6 @@ struct Arguments { headers: Option, data: Option, content_type: Option, - content_length: Option, raw: bool, insecure: bool, user: Option, @@ -156,7 +149,6 @@ fn run_delete( headers: call.get_flag(engine_state, stack, "headers")?, data: call.get_flag(engine_state, stack, "data")?, content_type: call.get_flag(engine_state, stack, "content-type")?, - content_length: call.get_flag(engine_state, stack, "content-length")?, raw: call.has_flag("raw"), insecure: call.has_flag("insecure"), user: call.get_flag(engine_state, stack, "user")?, @@ -176,19 +168,17 @@ fn helper( args: Arguments, ) -> Result { let span = args.url.span()?; - let (requested_url, url) = http_parse_url(call, span, args.url)?; + let (requested_url, _) = http_parse_url(call, span, args.url)?; let client = http_client(args.insecure); - let mut request = client.delete(url); + let mut request = client.delete(&requested_url); - if let Some(data) = args.data { - request = request_set_body(args.content_type, args.content_length, data, request)?; - } request = request_set_timeout(args.timeout, request)?; request = request_add_authorization_header(args.user, args.password, request); request = request_add_custom_headers(args.headers, request)?; - let response = request.send().and_then(|r| r.error_for_status()); + let response = send_request(request, span, args.data, args.content_type); + request_handle_response( engine_state, stack, diff --git a/crates/nu-command/src/network/http/get.rs b/crates/nu-command/src/network/http/get.rs index 9ed3068507..781e196d48 100644 --- a/crates/nu-command/src/network/http/get.rs +++ b/crates/nu-command/src/network/http/get.rs @@ -7,7 +7,7 @@ use nu_protocol::{ use crate::network::http::client::{ http_client, http_parse_url, request_add_authorization_header, request_add_custom_headers, - request_handle_response, request_set_body, request_set_timeout, + request_handle_response, request_set_timeout, send_request, }; #[derive(Clone)] @@ -46,12 +46,6 @@ impl Command for SubCommand { "the MIME type of content to post", Some('t'), ) - .named( - "content-length", - SyntaxShape::Any, - "the length of the content being posted", - Some('l'), - ) .named( "max-time", SyntaxShape::Int, @@ -138,7 +132,6 @@ struct Arguments { headers: Option, data: Option, content_type: Option, - content_length: Option, raw: bool, insecure: bool, user: Option, @@ -157,7 +150,6 @@ fn run_get( headers: call.get_flag(engine_state, stack, "headers")?, data: call.get_flag(engine_state, stack, "data")?, content_type: call.get_flag(engine_state, stack, "content-type")?, - content_length: call.get_flag(engine_state, stack, "content-length")?, raw: call.has_flag("raw"), insecure: call.has_flag("insecure"), user: call.get_flag(engine_state, stack, "user")?, @@ -176,19 +168,16 @@ fn helper( args: Arguments, ) -> Result { let span = args.url.span()?; - let (requested_url, url) = http_parse_url(call, span, args.url)?; + let (requested_url, _) = http_parse_url(call, span, args.url)?; let client = http_client(args.insecure); - let mut request = client.get(url); + let mut request = client.get(&requested_url); - if let Some(data) = args.data { - request = request_set_body(args.content_type, args.content_length, data, request)?; - } request = request_set_timeout(args.timeout, request)?; request = request_add_authorization_header(args.user, args.password, request); request = request_add_custom_headers(args.headers, request)?; - let response = request.send().and_then(|r| r.error_for_status()); + let response = send_request(request, span, args.data, args.content_type); request_handle_response( engine_state, stack, diff --git a/crates/nu-command/src/network/http/head.rs b/crates/nu-command/src/network/http/head.rs index 18ce4dffde..d78017dad9 100644 --- a/crates/nu-command/src/network/http/head.rs +++ b/crates/nu-command/src/network/http/head.rs @@ -7,7 +7,7 @@ use nu_protocol::{ use crate::network::http::client::{ http_client, http_parse_url, request_add_authorization_header, request_add_custom_headers, - request_handle_response_headers, request_set_timeout, + request_handle_response_headers, request_set_timeout, send_request, }; #[derive(Clone)] @@ -134,17 +134,17 @@ fn run_head( // The Option return a possible file extension which can be used in AutoConvert commands fn helper(call: &Call, args: Arguments) -> Result { let span = args.url.span()?; - let (requested_url, url) = http_parse_url(call, span, args.url)?; + let (requested_url, _) = http_parse_url(call, span, args.url)?; let client = http_client(args.insecure); - let mut request = client.head(url); + let mut request = client.head(&requested_url); request = request_set_timeout(args.timeout, request)?; request = request_add_authorization_header(args.user, args.password, request); request = request_add_custom_headers(args.headers, request)?; - let response = request.send().and_then(|r| r.error_for_status()); - request_handle_response_headers(span, &requested_url, response) + let response = send_request(request, span, None, None); + request_handle_response_headers(span, response) } #[cfg(test)] diff --git a/crates/nu-command/src/network/http/patch.rs b/crates/nu-command/src/network/http/patch.rs index 3a2b96b6ac..155cffa468 100644 --- a/crates/nu-command/src/network/http/patch.rs +++ b/crates/nu-command/src/network/http/patch.rs @@ -7,7 +7,7 @@ use nu_protocol::{ use crate::network::http::client::{ http_client, http_parse_url, request_add_authorization_header, request_add_custom_headers, - request_handle_response, request_set_body, request_set_timeout, + request_handle_response, request_set_timeout, send_request, }; #[derive(Clone)] @@ -42,12 +42,6 @@ impl Command for SubCommand { "the MIME type of content to post", Some('t'), ) - .named( - "content-length", - SyntaxShape::Any, - "the length of the content being posted", - Some('l'), - ) .named( "max-time", SyntaxShape::Int, @@ -127,7 +121,6 @@ struct Arguments { headers: Option, data: Value, content_type: Option, - content_length: Option, raw: bool, insecure: bool, user: Option, @@ -146,7 +139,6 @@ fn run_patch( headers: call.get_flag(engine_state, stack, "headers")?, data: call.req(engine_state, stack, 1)?, content_type: call.get_flag(engine_state, stack, "content-type")?, - content_length: call.get_flag(engine_state, stack, "content-length")?, raw: call.has_flag("raw"), insecure: call.has_flag("insecure"), user: call.get_flag(engine_state, stack, "user")?, @@ -166,17 +158,16 @@ fn helper( args: Arguments, ) -> Result { let span = args.url.span()?; - let (requested_url, url) = http_parse_url(call, span, args.url)?; + let (requested_url, _) = http_parse_url(call, span, args.url)?; let client = http_client(args.insecure); - let mut request = client.patch(url); + let mut request = client.patch(&requested_url); - request = request_set_body(args.content_type, args.content_length, args.data, request)?; request = request_set_timeout(args.timeout, request)?; request = request_add_authorization_header(args.user, args.password, request); request = request_add_custom_headers(args.headers, request)?; - let response = request.send().and_then(|r| r.error_for_status()); + let response = send_request(request, span, Some(args.data), args.content_type); request_handle_response( engine_state, stack, diff --git a/crates/nu-command/src/network/http/post.rs b/crates/nu-command/src/network/http/post.rs index 945108bd3f..80db01b404 100644 --- a/crates/nu-command/src/network/http/post.rs +++ b/crates/nu-command/src/network/http/post.rs @@ -7,7 +7,7 @@ use nu_protocol::{ use crate::network::http::client::{ http_client, http_parse_url, request_add_authorization_header, request_add_custom_headers, - request_handle_response, request_set_body, request_set_timeout, + request_handle_response, request_set_timeout, send_request, }; #[derive(Clone)] @@ -42,12 +42,6 @@ impl Command for SubCommand { "the MIME type of content to post", Some('t'), ) - .named( - "content-length", - SyntaxShape::Any, - "the length of the content being posted", - Some('l'), - ) .named( "max-time", SyntaxShape::Int, @@ -127,7 +121,6 @@ struct Arguments { headers: Option, data: Value, content_type: Option, - content_length: Option, raw: bool, insecure: bool, user: Option, @@ -146,7 +139,6 @@ fn run_post( headers: call.get_flag(engine_state, stack, "headers")?, data: call.req(engine_state, stack, 1)?, content_type: call.get_flag(engine_state, stack, "content-type")?, - content_length: call.get_flag(engine_state, stack, "content-length")?, raw: call.has_flag("raw"), insecure: call.has_flag("insecure"), user: call.get_flag(engine_state, stack, "user")?, @@ -166,17 +158,16 @@ fn helper( args: Arguments, ) -> Result { let span = args.url.span()?; - let (requested_url, url) = http_parse_url(call, span, args.url)?; + let (requested_url, _) = http_parse_url(call, span, args.url)?; let client = http_client(args.insecure); - let mut request = client.post(url); + let mut request = client.post(&requested_url); - request = request_set_body(args.content_type, args.content_length, args.data, request)?; request = request_set_timeout(args.timeout, request)?; request = request_add_authorization_header(args.user, args.password, request); request = request_add_custom_headers(args.headers, request)?; - let response = request.send().and_then(|r| r.error_for_status()); + let response = send_request(request, span, Some(args.data), args.content_type); request_handle_response( engine_state, stack, diff --git a/crates/nu-command/src/network/http/put.rs b/crates/nu-command/src/network/http/put.rs index 58779cc147..702d2e9a1c 100644 --- a/crates/nu-command/src/network/http/put.rs +++ b/crates/nu-command/src/network/http/put.rs @@ -7,7 +7,7 @@ use nu_protocol::{ use crate::network::http::client::{ http_client, http_parse_url, request_add_authorization_header, request_add_custom_headers, - request_handle_response, request_set_body, request_set_timeout, + request_handle_response, request_set_timeout, send_request, }; #[derive(Clone)] @@ -42,12 +42,6 @@ impl Command for SubCommand { "the MIME type of content to post", Some('t'), ) - .named( - "content-length", - SyntaxShape::Any, - "the length of the content being posted", - Some('l'), - ) .named( "max-time", SyntaxShape::Int, @@ -127,7 +121,6 @@ struct Arguments { headers: Option, data: Value, content_type: Option, - content_length: Option, raw: bool, insecure: bool, user: Option, @@ -146,7 +139,6 @@ fn run_put( headers: call.get_flag(engine_state, stack, "headers")?, data: call.req(engine_state, stack, 1)?, content_type: call.get_flag(engine_state, stack, "content-type")?, - content_length: call.get_flag(engine_state, stack, "content-length")?, raw: call.has_flag("raw"), insecure: call.has_flag("insecure"), user: call.get_flag(engine_state, stack, "user")?, @@ -166,17 +158,16 @@ fn helper( args: Arguments, ) -> Result { let span = args.url.span()?; - let (requested_url, url) = http_parse_url(call, span, args.url)?; + let (requested_url, _) = http_parse_url(call, span, args.url)?; let client = http_client(args.insecure); - let mut request = client.put(url); + let mut request = client.put(&requested_url); - request = request_set_body(args.content_type, args.content_length, args.data, request)?; request = request_set_timeout(args.timeout, request)?; request = request_add_authorization_header(args.user, args.password, request); request = request_add_custom_headers(args.headers, request)?; - let response = request.send().and_then(|r| r.error_for_status()); + let response = send_request(request, span, Some(args.data), args.content_type); request_handle_response( engine_state, stack, diff --git a/crates/nu-command/tests/commands/network/http/delete.rs b/crates/nu-command/tests/commands/network/http/delete.rs index 96eb505645..fceab9d423 100644 --- a/crates/nu-command/tests/commands/network/http/delete.rs +++ b/crates/nu-command/tests/commands/network/http/delete.rs @@ -1,6 +1,5 @@ use mockito::Server; use nu_test_support::{nu, pipeline}; -use reqwest::StatusCode; #[test] fn http_delete_is_success() { @@ -25,10 +24,7 @@ fn http_delete_is_success() { fn http_delete_failed_due_to_server_error() { let mut server = Server::new(); - let _mock = server - .mock("DELETE", "/") - .with_status(StatusCode::BAD_REQUEST.as_u16() as usize) - .create(); + let _mock = server.mock("DELETE", "/").with_status(400).create(); let actual = nu!(pipeline( format!( diff --git a/crates/nu-command/tests/commands/network/http/get.rs b/crates/nu-command/tests/commands/network/http/get.rs index 2adeab3571..021df025b5 100644 --- a/crates/nu-command/tests/commands/network/http/get.rs +++ b/crates/nu-command/tests/commands/network/http/get.rs @@ -1,6 +1,5 @@ use mockito::Server; use nu_test_support::{nu, pipeline}; -use reqwest::StatusCode; #[test] fn http_get_is_success() { @@ -25,10 +24,7 @@ fn http_get_is_success() { fn http_get_failed_due_to_server_error() { let mut server = Server::new(); - let _mock = server - .mock("GET", "/") - .with_status(StatusCode::BAD_REQUEST.as_u16() as usize) - .create(); + let _mock = server.mock("GET", "/").with_status(400).create(); let actual = nu!(pipeline( format!( diff --git a/crates/nu-command/tests/commands/network/http/head.rs b/crates/nu-command/tests/commands/network/http/head.rs index 64f3ec464d..0866d97e99 100644 --- a/crates/nu-command/tests/commands/network/http/head.rs +++ b/crates/nu-command/tests/commands/network/http/head.rs @@ -1,6 +1,5 @@ use mockito::Server; use nu_test_support::{nu, pipeline}; -use reqwest::StatusCode; #[test] fn http_head_is_success() { @@ -26,10 +25,7 @@ fn http_head_is_success() { fn http_head_failed_due_to_server_error() { let mut server = Server::new(); - let _mock = server - .mock("HEAD", "/") - .with_status(StatusCode::BAD_REQUEST.as_u16() as usize) - .create(); + let _mock = server.mock("HEAD", "/").with_status(400).create(); let actual = nu!(pipeline( format!( diff --git a/crates/nu-command/tests/commands/network/http/patch.rs b/crates/nu-command/tests/commands/network/http/patch.rs index 32ccd6eb80..53d8b946e0 100644 --- a/crates/nu-command/tests/commands/network/http/patch.rs +++ b/crates/nu-command/tests/commands/network/http/patch.rs @@ -1,6 +1,5 @@ use mockito::Server; use nu_test_support::{nu, pipeline}; -use reqwest::StatusCode; #[test] fn http_patch_is_success() { @@ -25,10 +24,7 @@ fn http_patch_is_success() { fn http_patch_failed_due_to_server_error() { let mut server = Server::new(); - let _mock = server - .mock("PATCH", "/") - .with_status(StatusCode::BAD_REQUEST.as_u16() as usize) - .create(); + let _mock = server.mock("PATCH", "/").with_status(400).create(); let actual = nu!(pipeline( format!( diff --git a/crates/nu-command/tests/commands/network/http/post.rs b/crates/nu-command/tests/commands/network/http/post.rs index 8cc31bd4f2..5f56121f52 100644 --- a/crates/nu-command/tests/commands/network/http/post.rs +++ b/crates/nu-command/tests/commands/network/http/post.rs @@ -1,6 +1,5 @@ use mockito::Server; use nu_test_support::{nu, pipeline}; -use reqwest::StatusCode; #[test] fn http_post_is_success() { @@ -25,10 +24,7 @@ fn http_post_is_success() { fn http_post_failed_due_to_server_error() { let mut server = Server::new(); - let _mock = server - .mock("POST", "/") - .with_status(StatusCode::BAD_REQUEST.as_u16() as usize) - .create(); + let _mock = server.mock("POST", "/").with_status(400).create(); let actual = nu!(pipeline( format!( diff --git a/crates/nu-command/tests/commands/network/http/put.rs b/crates/nu-command/tests/commands/network/http/put.rs index 6b4a8958dd..82d4ea771a 100644 --- a/crates/nu-command/tests/commands/network/http/put.rs +++ b/crates/nu-command/tests/commands/network/http/put.rs @@ -1,6 +1,5 @@ use mockito::Server; use nu_test_support::{nu, pipeline}; -use reqwest::StatusCode; #[test] fn http_put_is_success() { @@ -25,10 +24,7 @@ fn http_put_is_success() { fn http_put_failed_due_to_server_error() { let mut server = Server::new(); - let _mock = server - .mock("PUT", "/") - .with_status(StatusCode::BAD_REQUEST.as_u16() as usize) - .create(); + let _mock = server.mock("PUT", "/").with_status(400).create(); let actual = nu!(pipeline( format!(