-
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 http over unix domain sockets #392
Open
ducaale
wants to merge
26
commits into
master
Choose a base branch
from
http-over-unix-socket
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 9 commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
8ba7774
reduce lifetime of printer closure passed to client middleware
ducaale aa8fbf5
support http over unix domain sockets
ducaale fe56317
implement test server for http_unix
ducaale 531dba9
add initial tests for http_unix
ducaale bf4b1b8
fix clippy warnings
ducaale 80242c2
disable http_unix tests in windows
ducaale 8cee2fe
add middleware for managing cookies
ducaale 652e3df
add test for cookies
ducaale b6d59d9
avoid mocking host header
ducaale cb8d396
use shortened version of cfg unix check
ducaale c7fb645
throw an error if unix-socket used in unsupported os
ducaale e0791b3
provide complete example for unix-socket usage
ducaale f09a191
fix missing import
ducaale 67730e1
check that host header is passed
ducaale de52108
Merge branch 'master' into http-over-unix-socket
ducaale 0a80407
store unix_client in ClientWithMiddleware
ducaale 3d887f0
Merge branch 'master' into http-over-unix-socket
ducaale 2eb6367
Merge branch 'master' into http-over-unix-socket
ducaale 31c4420
warn or error if unix-socket used with unsupported option
ducaale 8bcbb0d
disable failing badssl.com tests
ducaale d601946
implement read timeout for unix_socket requests
ducaale c84e8ef
implement connect timeout for unix_socket requests
ducaale e362e7f
switch from read timeout to total timeout
ducaale 92df488
revert disabling badssl tests
ducaale bd8dbdd
Merge branch 'master' into http-over-unix-socket
ducaale 7db9b38
Merge branch 'master' into http-over-unix-socket
ducaale File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
use std::sync::Arc; | ||
|
||
use anyhow::Result; | ||
use reqwest::{ | ||
blocking::{Request, Response}, | ||
cookie::CookieStore, | ||
header, | ||
}; | ||
|
||
use crate::middleware::{Context, Middleware}; | ||
|
||
pub struct CookieMiddleware<T>(Arc<T>); | ||
|
||
impl<T> CookieMiddleware<T> { | ||
pub fn new(cookie_jar: Arc<T>) -> Self { | ||
CookieMiddleware(cookie_jar) | ||
} | ||
} | ||
|
||
impl<T: CookieStore> Middleware for CookieMiddleware<T> { | ||
fn handle(&mut self, mut ctx: Context, mut request: Request) -> Result<Response> { | ||
let url = request.url().clone(); | ||
|
||
if let Some(header) = self.0.cookies(&url) { | ||
request | ||
.headers_mut() | ||
.entry(header::COOKIE) | ||
.or_insert(header); | ||
} | ||
|
||
let response = self.next(&mut ctx, request)?; | ||
|
||
let mut cookies = response | ||
.headers() | ||
.get_all(header::SET_COOKIE) | ||
.iter() | ||
.peekable(); | ||
if cookies.peek().is_some() { | ||
self.0.set_cookies(&mut cookies, &url); | ||
} | ||
|
||
Ok(response) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
mod auth; | ||
mod buffer; | ||
mod cli; | ||
mod cookie; | ||
mod decoder; | ||
mod download; | ||
mod formatting; | ||
|
@@ -14,6 +15,8 @@ mod redirect; | |
mod request_items; | ||
mod session; | ||
mod to_curl; | ||
#[cfg(target_family = "unix")] | ||
ducaale marked this conversation as resolved.
Show resolved
Hide resolved
|
||
mod unix_socket; | ||
mod utils; | ||
mod vendored; | ||
|
||
|
@@ -27,6 +30,7 @@ use std::str::FromStr; | |
use std::sync::Arc; | ||
|
||
use anyhow::{anyhow, Context, Result}; | ||
use cookie::CookieMiddleware; | ||
use cookie_store::{CookieStore, RawCookie}; | ||
use redirect::RedirectFollower; | ||
use reqwest::blocking::Client; | ||
|
@@ -35,7 +39,6 @@ use reqwest::header::{ | |
}; | ||
use reqwest::tls; | ||
use url::Host; | ||
use utils::reason_phrase; | ||
|
||
use crate::auth::{Auth, DigestAuthMiddleware}; | ||
use crate::buffer::Buffer; | ||
|
@@ -45,7 +48,9 @@ use crate::middleware::ClientWithMiddleware; | |
use crate::printer::Printer; | ||
use crate::request_items::{Body, FORM_CONTENT_TYPE, JSON_ACCEPT, JSON_CONTENT_TYPE}; | ||
use crate::session::Session; | ||
use crate::utils::{test_mode, test_pretend_term, url_with_query}; | ||
#[cfg(target_family = "unix")] | ||
use crate::unix_socket::UnixSocket; | ||
use crate::utils::{reason_phrase, test_mode, test_pretend_term, url_with_query}; | ||
use crate::vendored::reqwest_cookie_store; | ||
|
||
#[cfg(not(any(feature = "native-tls", feature = "rustls")))] | ||
|
@@ -282,9 +287,6 @@ fn run(args: Cli) -> Result<i32> { | |
None => client, | ||
}; | ||
|
||
let cookie_jar = Arc::new(reqwest_cookie_store::CookieStoreMutex::default()); | ||
client = client.cookie_provider(cookie_jar.clone()); | ||
|
||
client = match (args.ipv4, args.ipv6) { | ||
(true, false) => client.local_address(IpAddr::from(Ipv4Addr::UNSPECIFIED)), | ||
(false, true) => client.local_address(IpAddr::from(Ipv6Addr::UNSPECIFIED)), | ||
|
@@ -336,6 +338,8 @@ fn run(args: Cli) -> Result<i32> { | |
log::trace!("{client:#?}"); | ||
let client = client.build()?; | ||
|
||
let cookie_jar = Arc::new(reqwest_cookie_store::CookieStoreMutex::default()); | ||
|
||
let mut session = match &args.session { | ||
Some(name_or_path) => Some( | ||
Session::load_session(url.clone(), name_or_path.clone(), args.is_session_read_only) | ||
|
@@ -538,42 +542,48 @@ fn run(args: Cli) -> Result<i32> { | |
printer.print_request_body(&mut request)?; | ||
} | ||
|
||
let mut client = ClientWithMiddleware::new(client); | ||
|
||
if !args.offline { | ||
let mut response = { | ||
let history_print = args.history_print.unwrap_or(print); | ||
let mut client = ClientWithMiddleware::new(&client); | ||
if args.all { | ||
client = client.with_printer(|prev_response, next_request| { | ||
if history_print.response_headers { | ||
printer.print_response_headers(prev_response)?; | ||
} | ||
if history_print.response_body { | ||
printer.print_response_body( | ||
prev_response, | ||
response_charset, | ||
response_mime, | ||
)?; | ||
printer.print_separator()?; | ||
} | ||
if history_print.response_meta { | ||
printer.print_response_meta(prev_response)?; | ||
} | ||
if history_print.request_headers { | ||
printer.print_request_headers(next_request, &*cookie_jar)?; | ||
} | ||
if history_print.request_body { | ||
printer.print_request_body(next_request)?; | ||
} | ||
Ok(()) | ||
}); | ||
} | ||
if args.follow { | ||
client = client.with(RedirectFollower::new(args.max_redirects.unwrap_or(10))); | ||
} | ||
if let Some(Auth::Digest(username, password)) = &auth { | ||
client = client.with(DigestAuthMiddleware::new(username, password)); | ||
} | ||
client.execute(request)? | ||
client = client.with(CookieMiddleware::new(cookie_jar.clone())); | ||
#[cfg(target_family = "unix")] | ||
if let Some(unix_socket) = args.unix_socket { | ||
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 is a fork of hyperlocal that adds support for windows but it might be better to wait until it is merged upstream |
||
client = client.with(UnixSocket::new(unix_socket)); | ||
} | ||
#[cfg(not(target_family = "unix"))] | ||
if let Some(_) = args.unix_socket { | ||
log::warn!("HTTP over Unix domain sockets is not supported on this platform"); | ||
ducaale marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
client.execute(request, |prev_response, next_request| { | ||
if !args.all { | ||
return Ok(()); | ||
} | ||
if history_print.response_headers { | ||
printer.print_response_headers(prev_response)?; | ||
} | ||
if history_print.response_body { | ||
printer.print_response_body(prev_response, response_charset, response_mime)?; | ||
printer.print_separator()?; | ||
} | ||
if history_print.response_meta { | ||
printer.print_response_meta(prev_response)?; | ||
} | ||
if history_print.request_headers { | ||
printer.print_request_headers(next_request, &*cookie_jar)?; | ||
} | ||
if history_print.request_body { | ||
printer.print_request_body(next_request)?; | ||
} | ||
Ok(()) | ||
})? | ||
}; | ||
|
||
let status = response.status(); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
With this API you still have to make up a hostname for the URL, like
curl
, and unlikegot
and the HTTPie plugin.AFAICT the typical use cases are for local services and not for proxies, meaning that the hostname is superfluous. But it also doesn't look like we're going to get a URL-based convention for this any time soon. And splitting it off into an option prevents redirect attacks. (Not sure how it should interact with sessions though... we need to look carefully at other areas of interference.)
A full command with the
:
shorthand might help users, e.g.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.
There is a good chance that unix domain sockets will be treated as a proxy in reqwest. This has the advantage that anything relying on hostname like cookies and
Host
header will keep working. Also, see denoland/deno#8821 (comment)However, I still think we can support
xh http://unix:/var/run/docker.sock:/containers/json
by treating it as a syntactic sugar forxh :/containers/json --unix-socket=/var/run/docker.sock
.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.
We can always add syntactic sugar later. Right now there doesn't seem to be any consensus about the URL format.
If it ever gets to the point where browsers start supporting UDS URLs (as a non-experimental feature) then we should follow suit.