-
Notifications
You must be signed in to change notification settings - Fork 101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support overwriting response's mime and charset #184
Changes from 4 commits
8abdaf3
06bb6d4
a356dbb
2618a6d
e8ed077
6cfb234
8e7fd1f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ use std::path::PathBuf; | |
use std::str::FromStr; | ||
use std::time::Duration; | ||
|
||
use encoding_rs::Encoding; | ||
use reqwest::{Method, Url}; | ||
use serde::{Deserialize, Serialize}; | ||
use structopt::clap::{self, arg_enum, AppSettings, Error, ErrorKind, Result}; | ||
|
@@ -65,6 +66,20 @@ pub struct Cli { | |
#[structopt(short = "s", long, value_name = "THEME", possible_values = &Theme::variants(), case_insensitive = true)] | ||
pub style: Option<Theme>, | ||
|
||
/// Override the response encoding for terminal display purposes. | ||
/// | ||
/// Example: `--response-charset=latin1` | ||
/// {n}{n}{n} | ||
#[structopt(long, value_name = "ENCODING", parse(try_from_str = parse_encoding))] | ||
pub response_charset: Option<&'static Encoding>, | ||
|
||
/// Override the response mime type for coloring and formatting for the terminal | ||
/// | ||
/// Example: `--response-mime=application/json` | ||
/// {n}{n}{n} | ||
#[structopt(long, value_name = "MIME_TYPE")] | ||
pub response_mime: Option<String>, | ||
|
||
/// String specifying what the output should contain. | ||
/// | ||
/// Use `H` and `B` for request header and body respectively, | ||
|
@@ -957,6 +972,52 @@ impl FromStr for HttpVersion { | |
} | ||
} | ||
|
||
// HTTPie recognizes some encoding names that encoding_rs doesn't e.g utf16 has to spelled as utf-16. | ||
// There are also some encodings which encoding_rs doesn't support but HTTPie does e.g utf-7. | ||
// See https://github.com/ducaale/xh/pull/184#pullrequestreview-787528027 | ||
fn parse_encoding(encoding: &str) -> Result<&'static Encoding> { | ||
let normalized_encoding = encoding.to_lowercase().replace( | ||
|c: char| (!c.is_alphanumeric() && c != '_' && c != '-' && c != ':'), | ||
"", | ||
); | ||
|
||
match normalized_encoding.as_str() { | ||
"u8" | "utf" => return Ok(encoding_rs::UTF_8), | ||
"u16" => return Ok(encoding_rs::UTF_16LE), | ||
_ => (), | ||
} | ||
|
||
for encoding in &[ | ||
&normalized_encoding, | ||
&normalized_encoding.replace(&['-', '_'][..], ""), | ||
&normalized_encoding.replace('_', "-"), | ||
&normalized_encoding.replace('-', "_"), | ||
] { | ||
if let Some(encoding) = Encoding::for_label(encoding.as_bytes()) { | ||
return Ok(encoding); | ||
} | ||
} | ||
|
||
{ | ||
let mut encoding = normalized_encoding.replace(&['-', '_'][..], ""); | ||
if let Some(first_digit_index) = encoding.find(|c: char| c.is_digit(10)) { | ||
encoding.insert(first_digit_index, '-'); | ||
if let Some(encoding) = Encoding::for_label(encoding.as_bytes()) { | ||
return Ok(encoding); | ||
} | ||
} | ||
} | ||
|
||
Err(Error::with_description( | ||
&format!( | ||
"{} is not a supported encoding, please refer to https://encoding.spec.whatwg.org/#names-and-labels\ | ||
for supported encodings", | ||
encoding | ||
), | ||
ErrorKind::InvalidValue, | ||
)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is missing a space after the link, and you get the bold red "error:" twice because structopt wraps another clap error around this one:
I think an error type of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are flags other than |
||
} | ||
|
||
/// Based on the function used by clap to abort | ||
fn safe_exit() -> ! { | ||
let _ = std::io::stdout().lock().flush(); | ||
|
@@ -1283,4 +1344,19 @@ mod tests { | |
let cli = parse(&["--no-check-status", "--check-status", ":"]).unwrap(); | ||
assert_eq!(cli.check_status, Some(true)); | ||
} | ||
|
||
#[test] | ||
fn parse_encoding_label() { | ||
assert_eq!( | ||
parse_encoding("~~~~UtF////16@@").unwrap(), | ||
encoding_rs::UTF_16LE | ||
); | ||
assert_eq!(parse_encoding("utf_8").unwrap(), encoding_rs::UTF_8); | ||
assert_eq!(parse_encoding("utf8").unwrap(), encoding_rs::UTF_8); | ||
assert_eq!(parse_encoding("utf-8").unwrap(), encoding_rs::UTF_8); | ||
assert_eq!( | ||
parse_encoding("iso8859_6").unwrap(), | ||
encoding_rs::ISO_8859_6 | ||
); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are there any test cases you think are worth adding here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd also try And maybe I guess that's a lot of cases. You could put them in a const |
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
encoding_rs
associates the labelutf-16
withUTF_16LE
but I am not sure if it is the same in Python.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also don't think that
encoding_rs
supportsutf-32
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On my phone (ARM) it's little-endian:
I wouldn't be surprised if it depended on the machine's architecture. x86 is also little-endian so we'd agree on most machines.
In any case, encoding-rs is made for the web, so if it disagrees with Python then it's probably Python which is wrong.