mirror of
https://github.com/facebook/sapling.git
synced 2024-10-10 16:57:49 +03:00
http_client: add CLI for testing
Summary: Add a simple CLI to allow the HTTP client to be tested manually. Reviewed By: quark-zju Differential Revision: D22228930 fbshipit-source-id: 12fea3131ec6d8c3df4457fb74a09ea52f42c066
This commit is contained in:
parent
e054376937
commit
19c55df1fd
@ -1,19 +1,29 @@
|
||||
# @generated by autocargo from //eden/scm/lib/http_client:http_client
|
||||
# @generated by autocargo from //eden/scm/lib/http_client:[http_cli,http_client]
|
||||
[package]
|
||||
name = "http_client"
|
||||
edition = "2018"
|
||||
version = "0.1.0"
|
||||
include = ["src/**/*.rs"]
|
||||
include = ["src/**/*.rs", "src/bin/cli.rs"]
|
||||
|
||||
[lib]
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "http_cli"
|
||||
path = "src/bin/cli.rs"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
atty = "0.2"
|
||||
curl = { version = "0.4", features = ["http2"] }
|
||||
env_logger = "0.7"
|
||||
http = "0.2"
|
||||
log = { version = "0.4.8", features = ["kv_unstable"] }
|
||||
once_cell = "1.4"
|
||||
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||
serde_cbor = "0.11"
|
||||
serde_json = "1.0"
|
||||
structopt = "0.3.7"
|
||||
thiserror = "1.0"
|
||||
url = "2.1.0"
|
||||
|
||||
|
178
eden/scm/lib/http_client/src/bin/cli.rs
Normal file
178
eden/scm/lib/http_client/src/bin/cli.rs
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This software may be used and distributed according to the terms of the
|
||||
* GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
use std::env;
|
||||
use std::io::{prelude::*, stdin, stdout};
|
||||
|
||||
use anyhow::Result;
|
||||
use structopt::StructOpt;
|
||||
use url::Url;
|
||||
|
||||
use http_client::{Request, Response};
|
||||
|
||||
const CERT_ENV_VAR: &str = "CERT";
|
||||
const KEY_ENV_VAR: &str = "KEY";
|
||||
const CA_ENV_VAR: &str = "CA";
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt(name = "http_cli", about = "Send HTTP requests")]
|
||||
enum Method {
|
||||
#[structopt(about = "Send a GET request")]
|
||||
Get(Args),
|
||||
#[structopt(about = "Send a HEAD request")]
|
||||
Head(Args),
|
||||
#[structopt(about = "Send a POST request")]
|
||||
Post(Args),
|
||||
#[structopt(about = "Send a PUT request")]
|
||||
Put(Args),
|
||||
}
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
struct Args {
|
||||
#[structopt(help = "Request URL")]
|
||||
url: String,
|
||||
#[structopt(
|
||||
long,
|
||||
short = "H",
|
||||
help = "Headers as a series of \"Header-Name: Value\" strings"
|
||||
)]
|
||||
headers: Vec<String>,
|
||||
}
|
||||
|
||||
impl Args {
|
||||
fn url(&self) -> Result<Url> {
|
||||
Ok(Url::parse(&self.url)?)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
env_logger::init();
|
||||
match Method::from_args() {
|
||||
Method::Get(args) => cmd_get(args),
|
||||
Method::Head(args) => cmd_head(args),
|
||||
Method::Post(args) => cmd_post(args),
|
||||
Method::Put(args) => cmd_put(args),
|
||||
}
|
||||
}
|
||||
|
||||
fn cmd_get(args: Args) -> Result<()> {
|
||||
let url = args.url()?;
|
||||
|
||||
let req = Request::get(&url);
|
||||
let req = add_headers(req, &args.headers);
|
||||
|
||||
let creds = get_creds();
|
||||
let ca = get_ca();
|
||||
let req = configure_tls(req, &creds, &ca)?;
|
||||
|
||||
write_response(req.send()?)
|
||||
}
|
||||
|
||||
fn cmd_head(args: Args) -> Result<()> {
|
||||
let url = args.url()?;
|
||||
|
||||
let req = Request::head(&url);
|
||||
let req = add_headers(req, &args.headers);
|
||||
|
||||
let creds = get_creds();
|
||||
let ca = get_ca();
|
||||
let req = configure_tls(req, &creds, &ca)?;
|
||||
|
||||
write_response(req.send()?)
|
||||
}
|
||||
|
||||
fn cmd_post(args: Args) -> Result<()> {
|
||||
let url = args.url()?;
|
||||
|
||||
eprintln!("Reading payload from stdin");
|
||||
let body = read_input()?;
|
||||
|
||||
let req = Request::post(&url).body(body);
|
||||
let req = add_headers(req, &args.headers);
|
||||
|
||||
let creds = get_creds();
|
||||
let ca = get_ca();
|
||||
let req = configure_tls(req, &creds, &ca)?;
|
||||
|
||||
write_response(req.send()?)
|
||||
}
|
||||
|
||||
fn cmd_put(args: Args) -> Result<()> {
|
||||
let url = args.url()?;
|
||||
|
||||
eprintln!("Reading payload from stdin");
|
||||
let body = read_input()?;
|
||||
|
||||
let req = Request::put(&url).body(body);
|
||||
let req = add_headers(req, &args.headers);
|
||||
|
||||
let creds = get_creds();
|
||||
let ca = get_ca();
|
||||
let req = configure_tls(req, &creds, &ca)?;
|
||||
|
||||
write_response(req.send()?)
|
||||
}
|
||||
|
||||
fn read_input() -> Result<Vec<u8>> {
|
||||
let mut buf = Vec::new();
|
||||
stdin().read_to_end(&mut buf)?;
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
fn write_response(res: Response) -> Result<()> {
|
||||
eprintln!("Status: {}", res.status);
|
||||
eprintln!("{:?}", &res.headers);
|
||||
|
||||
if atty::is(atty::Stream::Stdout) {
|
||||
println!("{}", String::from_utf8_lossy(&res.body).escape_default())
|
||||
} else {
|
||||
stdout().write_all(&res.body)?;
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn configure_tls<'a>(
|
||||
mut req: Request<'a>,
|
||||
creds: &'a Option<(String, String)>,
|
||||
ca: &'a Option<String>,
|
||||
) -> Result<Request<'a>> {
|
||||
if let Some((cert, key)) = creds {
|
||||
req = req.creds(cert, key)?;
|
||||
}
|
||||
if let Some(ca) = ca {
|
||||
req = req.cainfo(ca)?;
|
||||
}
|
||||
Ok(req)
|
||||
}
|
||||
|
||||
fn get_creds() -> Option<(String, String)> {
|
||||
let cert = env::var(CERT_ENV_VAR).ok()?;
|
||||
let key = env::var(KEY_ENV_VAR).ok()?;
|
||||
Some((cert, key))
|
||||
}
|
||||
|
||||
fn get_ca() -> Option<String> {
|
||||
env::var(CA_ENV_VAR).ok()
|
||||
}
|
||||
|
||||
fn add_headers<'a>(mut req: Request<'a>, headers: &'a [String]) -> Request<'a> {
|
||||
for header in headers {
|
||||
let (name, value) = split_header(header);
|
||||
req = req.header(name, value);
|
||||
}
|
||||
req
|
||||
}
|
||||
|
||||
fn split_header(header: &str) -> (&str, &str) {
|
||||
let parts = header.splitn(2, ':').collect::<Vec<_>>();
|
||||
if parts.len() > 1 {
|
||||
(parts[0], parts[1].trim_start())
|
||||
} else {
|
||||
(parts[0], "")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user