Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ percent-encoding = "2.3.1"
sanitize-filename = "0.6.0"

[dependencies.reqwest]
version = "0.12.22"
version = "0.12.23"
default-features = false
features = ["json", "multipart", "blocking", "socks", "cookies", "http2", "macos-system-configuration"]

Expand Down
8 changes: 7 additions & 1 deletion src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,12 @@ Example: --print=Hb"
#[clap(short = '6', long)]
pub ipv6: bool,

/// Connect using a Unix domain socket.
///
/// Example: xh :/index.html --unix-socket=/var/run/temp.sock
#[clap(long, value_name = "FILE")]
pub unix_socket: Option<PathBuf>,

/// Do not attempt to read stdin.
///
/// This disables the default behaviour of reading the request body from stdin
Expand Down Expand Up @@ -1216,7 +1222,7 @@ pub enum Generate {
/// BE instead.
fn parse_encoding(encoding: &str) -> anyhow::Result<&'static Encoding> {
let normalized_encoding = encoding.to_lowercase().replace(
|c: char| (!c.is_alphanumeric() && c != '_' && c != '-' && c != ':'),
|c: char| !c.is_alphanumeric() && c != '_' && c != '-' && c != ':',
"",
);

Expand Down
12 changes: 12 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,18 @@ fn run(args: Cli) -> Result<ExitCode> {
};
}

#[cfg(unix)]
if let Some(socket_path) = args.unix_socket {
client = client.unix_socket(socket_path);
}

#[cfg(not(unix))]
if args.unix_socket.is_some() {
return Err(anyhow::anyhow!(
"--unix-socket is not supported on this platform"
));
}

for resolve in args.resolve {
client = client.resolve(&resolve.domain, SocketAddr::new(resolve.addr, 0));
}
Expand Down
5 changes: 5 additions & 0 deletions src/to_curl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,11 @@ pub fn translate(args: Cli) -> Result<Command> {
cmd.arg(interface);
};

if let Some(unix_socket) = args.unix_socket {
cmd.arg("--unix-socket");
cmd.arg(unix_socket);
}

if !args.resolve.is_empty() {
let port = url
.port_or_known_default()
Expand Down
1 change: 1 addition & 0 deletions tests/cases/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod compress_request_body;
mod download;
mod logging;
mod unix_socket;
132 changes: 132 additions & 0 deletions tests/cases/unix_socket.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#[cfg(unix)]
use indoc::indoc;

use crate::prelude::*;

#[cfg(not(unix))]
#[test]
fn error_on_unsupported_platform() {
use predicates::str::contains;

get_command()
.arg("--unix-socket=/tmp/missing.sock")
.arg(":/index.html")
.assert()
.failure()
.stderr(contains("--unix-socket is not supported on this platform"));
}

#[cfg(unix)]
#[test]
fn json_post() {
let server = server::http_unix(|req| async move {
assert_eq!(req.method(), "POST");
assert_eq!(req.headers()["Content-Type"], "application/json");
assert_eq!(req.body_as_string().await, "{\"foo\":\"bar\"}");

hyper::Response::builder()
.header(hyper::header::CONTENT_TYPE, "application/json")
.body(r#"{"status":"ok"}"#.into())
.unwrap()
});

get_command()
.arg("--print=b")
.arg("--pretty=format")
.arg("post")
.arg("http://example.com")
.arg(format!(
"--unix-socket={}",
server.socket_path().to_string_lossy()
))
.arg("foo=bar")
.assert()
.stdout(indoc! {r#"
{
"status": "ok"
}


"#});
}

#[cfg(unix)]
#[test]
fn redirects_stay_on_same_server() {
let server = server::http_unix(|req| async move {
match req.uri().to_string().as_str() {
"/first_page" => hyper::Response::builder()
.status(302)
.header("Date", "N/A")
.header("Location", "http://localhost:8000/second_page")
.body("redirecting...".into())
.unwrap(),
"/second_page" => hyper::Response::builder()
.status(302)
.header("Date", "N/A")
.header("Location", "/third_page")
.body("redirecting...".into())
.unwrap(),
"/third_page" => hyper::Response::builder()
.header("Date", "N/A")
.body("final destination".into())
.unwrap(),
_ => panic!("unknown path"),
}
});

get_command()
.arg("http://example.com/first_page")
.arg(format!(
"--unix-socket={}",
server.socket_path().to_string_lossy()
))
.arg("--follow")
.arg("--verbose")
.arg("--all")
.assert()
.stdout(indoc! {r#"
GET /first_page HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Connection: keep-alive
Host: http.mock
User-Agent: xh/0.0.0 (test mode)

HTTP/1.1 302 Found
Content-Length: 14
Date: N/A
Location: http://localhost:8000/second_page

redirecting...

GET /second_page HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Connection: keep-alive
Host: http.mock
User-Agent: xh/0.0.0 (test mode)

HTTP/1.1 302 Found
Content-Length: 14
Date: N/A
Location: /third_page

redirecting...

GET /third_page HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Connection: keep-alive
Host: http.mock
User-Agent: xh/0.0.0 (test mode)

HTTP/1.1 200 OK
Content-Length: 17
Date: N/A

final destination
"#});

server.assert_hits(3);
}
Loading
Loading