diff --git a/crates/nu-command/src/network/http/client.rs b/crates/nu-command/src/network/http/client.rs index 0027101528..75ef8c4897 100644 --- a/crates/nu-command/src/network/http/client.rs +++ b/crates/nu-command/src/network/http/client.rs @@ -4,7 +4,6 @@ use base64::{ engine::{general_purpose::PAD, GeneralPurpose}, Engine, }; -use fancy_regex::Regex; use multipart_rs::MultipartWriter; use nu_engine::command_prelude::*; use nu_protocol::{ByteStream, LabeledError, Signals}; @@ -561,14 +560,12 @@ fn transform_response_using_content_type( resp: Response, content_type: &str, ) -> Result { - let regex = Regex::new("\"").expect("Failed to create regex"); - let content_type_trim = regex.replace_all(content_type, "").to_string(); - - let content_type = mime::Mime::from_str(&content_type_trim).map_err(|err| { - LabeledError::new(err.to_string()) - .with_help("given unknown MIME type, or error parsing MIME type") - .with_label(format!("MIME type unknown: {content_type_trim}"), span) - })?; + let content_type = mime::Mime::from_str(content_type) + // there are invalid content types in the wild, so we try to recover + // Example: `Content-Type: "text/plain"; charset="utf8"` (note the quotes) + .or_else(|_| mime::Mime::from_str(&content_type.replace('"', ""))) + .or_else(|_| mime::Mime::from_str("text/plain")) + .expect("Failed to parse content type, and failed to default to text/plain"); let ext = match (content_type.type_(), content_type.subtype()) { (mime::TEXT, mime::PLAIN) => { diff --git a/crates/nu-command/tests/commands/network/http/get.rs b/crates/nu-command/tests/commands/network/http/get.rs index bb7a8a4661..e1f1132efa 100644 --- a/crates/nu-command/tests/commands/network/http/get.rs +++ b/crates/nu-command/tests/commands/network/http/get.rs @@ -273,3 +273,46 @@ fn http_get_self_signed_override() { let actual = nu!("http get --insecure https://self-signed.badssl.com/"); assert!(actual.out.contains("")); } + +#[test] +fn http_get_with_invalid_mime_type() { + let mut server = Server::new(); + + let _mock = server + .mock("GET", "/foo.nuon") + .with_status(200) + // `what&ever` is not a parseable MIME type + .with_header("content-type", "what&ever") + .with_body("[1 2 3]") + .create(); + + // but `from nuon` is a known command in nu, so we take `foo.{ext}` and pass it to `from {ext}` + let actual = nu!(pipeline( + format!( + r#"http get {url}/foo.nuon | to json --raw"#, + url = server.url() + ) + .as_str() + )); + + assert_eq!(actual.out, "[1,2,3]"); +} + +#[test] +fn http_get_with_unknown_mime_type() { + let mut server = Server::new(); + let _mock = server + .mock("GET", "/foo") + .with_status(200) + // `application/nuon` is not an IANA-registered MIME type + .with_header("content-type", "application/nuon") + .with_body("[1 2 3]") + .create(); + + // but `from nuon` is a known command in nu, so we take `{garbage}/{whatever}` and pass it to `from {whatever}` + let actual = nu!(pipeline( + format!(r#"http get {url}/foo | to json --raw"#, url = server.url()).as_str() + )); + + assert_eq!(actual.out, "[1,2,3]"); +}