mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-11-23 20:12:09 +03:00
Parse more curl options
This commit is contained in:
parent
d9fd713ab5
commit
3e37931a49
@ -15,7 +15,19 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
use clap::ArgAction;
|
||||
use clap::{value_parser, ArgAction};
|
||||
|
||||
pub fn compressed() -> clap::Arg {
|
||||
clap::Arg::new("compressed").long("compressed").num_args(0)
|
||||
}
|
||||
|
||||
pub fn data() -> clap::Arg {
|
||||
clap::Arg::new("data")
|
||||
.long("data")
|
||||
.short('d')
|
||||
.value_name("data")
|
||||
.num_args(1)
|
||||
}
|
||||
|
||||
pub fn headers() -> clap::Arg {
|
||||
clap::Arg::new("headers")
|
||||
@ -26,6 +38,29 @@ pub fn headers() -> clap::Arg {
|
||||
.num_args(1)
|
||||
}
|
||||
|
||||
pub fn insecure() -> clap::Arg {
|
||||
clap::Arg::new("insecure")
|
||||
.long("insecure")
|
||||
.short('k')
|
||||
.num_args(0)
|
||||
}
|
||||
|
||||
pub fn location() -> clap::Arg {
|
||||
clap::Arg::new("location")
|
||||
.long("location")
|
||||
.short('L')
|
||||
.num_args(0)
|
||||
}
|
||||
|
||||
pub fn max_redirects() -> clap::Arg {
|
||||
clap::Arg::new("max_redirects")
|
||||
.long("max-redirs")
|
||||
.value_name("NUM")
|
||||
.allow_hyphen_values(true)
|
||||
.value_parser(value_parser!(i32).range(-1..))
|
||||
.num_args(1)
|
||||
}
|
||||
|
||||
pub fn method() -> clap::Arg {
|
||||
clap::Arg::new("method")
|
||||
.long("request")
|
||||
|
@ -17,9 +17,28 @@
|
||||
*/
|
||||
use clap::ArgMatches;
|
||||
|
||||
pub fn body(arg_matches: &ArgMatches) -> Option<String> {
|
||||
match get_string(arg_matches, "data") {
|
||||
None => None,
|
||||
Some(v) => {
|
||||
if let Some(filename) = v.strip_prefix('@') {
|
||||
Some(format!("file, {filename};"))
|
||||
} else {
|
||||
Some(format!("```{v}```"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn method(arg_matches: &ArgMatches) -> String {
|
||||
match get_string(arg_matches, "method") {
|
||||
None => "GET".to_string(),
|
||||
None => {
|
||||
if arg_matches.contains_id("data") {
|
||||
"POST".to_string()
|
||||
} else {
|
||||
"GET".to_string()
|
||||
}
|
||||
}
|
||||
Some(v) => v,
|
||||
}
|
||||
}
|
||||
@ -34,18 +53,62 @@ pub fn url(arg_matches: &ArgMatches) -> String {
|
||||
}
|
||||
|
||||
pub fn headers(arg_matches: &ArgMatches) -> Vec<String> {
|
||||
match get_strings(arg_matches, "headers") {
|
||||
let mut headers = match get_strings(arg_matches, "headers") {
|
||||
None => vec![],
|
||||
Some(v) => v,
|
||||
};
|
||||
if !has_content_type(&headers) {
|
||||
if let Some(data) = get_string(arg_matches, "data") {
|
||||
if !data.starts_with('@') {
|
||||
headers.push("Content-Type: application/x-www-form-urlencoded".to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
headers
|
||||
}
|
||||
|
||||
pub fn get_string(matches: &ArgMatches, name: &str) -> Option<String> {
|
||||
pub fn options(arg_matches: &ArgMatches) -> Vec<String> {
|
||||
let mut options = vec![];
|
||||
if has_flag(arg_matches, "compressed") {
|
||||
options.push("compressed: true".to_string());
|
||||
}
|
||||
if has_flag(arg_matches, "location") {
|
||||
options.push("location: true".to_string());
|
||||
}
|
||||
if has_flag(arg_matches, "insecure") {
|
||||
options.push("insecure: true".to_string());
|
||||
}
|
||||
if let Some(value) = get::<i32>(arg_matches, "max_redirects") {
|
||||
options.push(format!("max-redirs: {value}"));
|
||||
}
|
||||
options
|
||||
}
|
||||
|
||||
fn has_content_type(headers: &Vec<String>) -> bool {
|
||||
for header in headers {
|
||||
if header.starts_with("Content-Type") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn has_flag(matches: &ArgMatches, name: &str) -> bool {
|
||||
matches.get_one::<bool>(name) == Some(&true)
|
||||
}
|
||||
|
||||
/// Returns an optional value of type `T` from the command line `matches` given the option `name`.
|
||||
fn get<T: Clone + Send + Sync + 'static>(matches: &ArgMatches, name: &str) -> Option<T> {
|
||||
matches.get_one::<T>(name).cloned()
|
||||
}
|
||||
|
||||
fn get_string(matches: &ArgMatches, name: &str) -> Option<String> {
|
||||
matches.get_one::<String>(name).map(|x| x.to_string())
|
||||
}
|
||||
|
||||
/// Returns an optional list of `String` from the command line `matches` given the option `name`.
|
||||
pub fn get_strings(matches: &ArgMatches, name: &str) -> Option<Vec<String>> {
|
||||
fn get_strings(matches: &ArgMatches, name: &str) -> Option<Vec<String>> {
|
||||
matches
|
||||
.get_many::<String>(name)
|
||||
.map(|v| v.map(|x| x.to_string()).collect())
|
||||
|
@ -22,7 +22,12 @@ mod matches;
|
||||
|
||||
pub fn parse(s: &str) -> Result<String, String> {
|
||||
let mut command = clap::Command::new("curl")
|
||||
.arg(commands::compressed())
|
||||
.arg(commands::data())
|
||||
.arg(commands::headers())
|
||||
.arg(commands::insecure())
|
||||
.arg(commands::location())
|
||||
.arg(commands::max_redirects())
|
||||
.arg(commands::method())
|
||||
.arg(commands::url());
|
||||
|
||||
@ -35,15 +40,32 @@ pub fn parse(s: &str) -> Result<String, String> {
|
||||
let method = matches::method(&arg_matches);
|
||||
let url = matches::url(&arg_matches);
|
||||
let headers = matches::headers(&arg_matches);
|
||||
let s = format(&method, &url, headers);
|
||||
let options = matches::options(&arg_matches);
|
||||
let body = matches::body(&arg_matches);
|
||||
let s = format(&method, &url, headers, options, body);
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
fn format(method: &str, url: &str, headers: Vec<String>) -> String {
|
||||
fn format(
|
||||
method: &str,
|
||||
url: &str,
|
||||
headers: Vec<String>,
|
||||
options: Vec<String>,
|
||||
body: Option<String>,
|
||||
) -> String {
|
||||
let mut s = format!("{method} {url}");
|
||||
for header in headers {
|
||||
s.push_str(format!("\n{header}").as_str());
|
||||
}
|
||||
if !options.is_empty() {
|
||||
s.push_str("\n[Options]");
|
||||
for option in options {
|
||||
s.push_str(format!("\n{option}").as_str());
|
||||
}
|
||||
}
|
||||
if let Some(body) = body {
|
||||
s.push_str(format!("\n{body}").as_str());
|
||||
}
|
||||
s.push('\n');
|
||||
s
|
||||
}
|
||||
@ -75,4 +97,79 @@ Test: '
|
||||
hurl_str
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_post_format_params() {
|
||||
let hurl_str = r#"POST http://localhost:3000/data
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
```param1=value1¶m2=value2```
|
||||
"#;
|
||||
assert_eq!(
|
||||
parse("curl http://localhost:3000/data -d 'param1=value1¶m2=value2'").unwrap(),
|
||||
hurl_str
|
||||
);
|
||||
assert_eq!(
|
||||
parse("curl -X POST http://localhost:3000/data -H 'Content-Type: application/x-www-form-urlencoded' --data 'param1=value1¶m2=value2'").unwrap(),
|
||||
hurl_str
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_post_json() {
|
||||
let hurl_str = r#"POST http://localhost:3000/data
|
||||
Content-Type: application/json
|
||||
```{"key1":"value1", "key2":"value2"}```
|
||||
"#;
|
||||
assert_eq!(
|
||||
parse(r#"curl -d '{"key1":"value1", "key2":"value2"}' -H 'Content-Type: application/json' -X POST http://localhost:3000/data"#).unwrap(),
|
||||
hurl_str
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_post_file() {
|
||||
let hurl_str = r#"POST http://example.com/
|
||||
file, filename;
|
||||
"#;
|
||||
assert_eq!(
|
||||
parse(r#"curl --data @filename http://example.com/"#).unwrap(),
|
||||
hurl_str
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_redirect() {
|
||||
let hurl_str = r#"GET http://localhost:8000/redirect-absolute
|
||||
[Options]
|
||||
location: true
|
||||
"#;
|
||||
assert_eq!(
|
||||
parse(r#"curl -L http://localhost:8000/redirect-absolute"#).unwrap(),
|
||||
hurl_str
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_insecure() {
|
||||
let hurl_str = r#"GET https://localhost:8001/hello
|
||||
[Options]
|
||||
insecure: true
|
||||
"#;
|
||||
assert_eq!(
|
||||
parse(r#"curl -k https://localhost:8001/hello"#).unwrap(),
|
||||
hurl_str
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_max_redirects() {
|
||||
let hurl_str = r#"GET https://localhost:8001/hello
|
||||
[Options]
|
||||
max-redirs: 10
|
||||
"#;
|
||||
assert_eq!(
|
||||
parse(r#"curl https://localhost:8001/hello --max-redirs 10"#).unwrap(),
|
||||
hurl_str
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user