wreq-rb 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Cargo.lock +2688 -0
- data/Cargo.toml +6 -0
- data/README.md +179 -0
- data/ext/wreq_rb/Cargo.toml +39 -0
- data/ext/wreq_rb/extconf.rb +22 -0
- data/ext/wreq_rb/src/client.rs +565 -0
- data/ext/wreq_rb/src/error.rs +25 -0
- data/ext/wreq_rb/src/lib.rs +20 -0
- data/ext/wreq_rb/src/response.rs +132 -0
- data/lib/wreq-rb/version.rb +5 -0
- data/lib/wreq-rb.rb +17 -0
- data/patches/0001-add-transfer-size-tracking.patch +292 -0
- data/vendor/wreq/Cargo.toml +306 -0
- data/vendor/wreq/LICENSE +202 -0
- data/vendor/wreq/README.md +122 -0
- data/vendor/wreq/examples/cert_store.rs +77 -0
- data/vendor/wreq/examples/connect_via_lower_priority_tokio_runtime.rs +258 -0
- data/vendor/wreq/examples/emulation.rs +118 -0
- data/vendor/wreq/examples/form.rs +14 -0
- data/vendor/wreq/examples/http1_websocket.rs +37 -0
- data/vendor/wreq/examples/http2_websocket.rs +45 -0
- data/vendor/wreq/examples/json_dynamic.rs +41 -0
- data/vendor/wreq/examples/json_typed.rs +47 -0
- data/vendor/wreq/examples/keylog.rs +16 -0
- data/vendor/wreq/examples/request_with_emulation.rs +115 -0
- data/vendor/wreq/examples/request_with_interface.rs +37 -0
- data/vendor/wreq/examples/request_with_local_address.rs +16 -0
- data/vendor/wreq/examples/request_with_proxy.rs +13 -0
- data/vendor/wreq/examples/request_with_redirect.rs +22 -0
- data/vendor/wreq/examples/request_with_version.rs +15 -0
- data/vendor/wreq/examples/tor_socks.rs +24 -0
- data/vendor/wreq/examples/unix_socket.rs +33 -0
- data/vendor/wreq/src/client/body.rs +304 -0
- data/vendor/wreq/src/client/conn/conn.rs +231 -0
- data/vendor/wreq/src/client/conn/connector.rs +549 -0
- data/vendor/wreq/src/client/conn/http.rs +1023 -0
- data/vendor/wreq/src/client/conn/proxy/socks.rs +233 -0
- data/vendor/wreq/src/client/conn/proxy/tunnel.rs +260 -0
- data/vendor/wreq/src/client/conn/proxy.rs +39 -0
- data/vendor/wreq/src/client/conn/tls_info.rs +98 -0
- data/vendor/wreq/src/client/conn/uds.rs +44 -0
- data/vendor/wreq/src/client/conn/verbose.rs +149 -0
- data/vendor/wreq/src/client/conn.rs +323 -0
- data/vendor/wreq/src/client/core/body/incoming.rs +485 -0
- data/vendor/wreq/src/client/core/body/length.rs +118 -0
- data/vendor/wreq/src/client/core/body.rs +34 -0
- data/vendor/wreq/src/client/core/common/buf.rs +149 -0
- data/vendor/wreq/src/client/core/common/rewind.rs +141 -0
- data/vendor/wreq/src/client/core/common/watch.rs +76 -0
- data/vendor/wreq/src/client/core/common.rs +3 -0
- data/vendor/wreq/src/client/core/conn/http1.rs +342 -0
- data/vendor/wreq/src/client/core/conn/http2.rs +307 -0
- data/vendor/wreq/src/client/core/conn.rs +11 -0
- data/vendor/wreq/src/client/core/dispatch.rs +299 -0
- data/vendor/wreq/src/client/core/error.rs +435 -0
- data/vendor/wreq/src/client/core/ext.rs +201 -0
- data/vendor/wreq/src/client/core/http1.rs +178 -0
- data/vendor/wreq/src/client/core/http2.rs +483 -0
- data/vendor/wreq/src/client/core/proto/h1/conn.rs +988 -0
- data/vendor/wreq/src/client/core/proto/h1/decode.rs +1170 -0
- data/vendor/wreq/src/client/core/proto/h1/dispatch.rs +684 -0
- data/vendor/wreq/src/client/core/proto/h1/encode.rs +580 -0
- data/vendor/wreq/src/client/core/proto/h1/io.rs +879 -0
- data/vendor/wreq/src/client/core/proto/h1/role.rs +694 -0
- data/vendor/wreq/src/client/core/proto/h1.rs +104 -0
- data/vendor/wreq/src/client/core/proto/h2/client.rs +650 -0
- data/vendor/wreq/src/client/core/proto/h2/ping.rs +539 -0
- data/vendor/wreq/src/client/core/proto/h2.rs +379 -0
- data/vendor/wreq/src/client/core/proto/headers.rs +138 -0
- data/vendor/wreq/src/client/core/proto.rs +58 -0
- data/vendor/wreq/src/client/core/rt/bounds.rs +57 -0
- data/vendor/wreq/src/client/core/rt/timer.rs +150 -0
- data/vendor/wreq/src/client/core/rt/tokio.rs +99 -0
- data/vendor/wreq/src/client/core/rt.rs +25 -0
- data/vendor/wreq/src/client/core/upgrade.rs +267 -0
- data/vendor/wreq/src/client/core.rs +16 -0
- data/vendor/wreq/src/client/emulation.rs +161 -0
- data/vendor/wreq/src/client/http/client/error.rs +142 -0
- data/vendor/wreq/src/client/http/client/exec.rs +29 -0
- data/vendor/wreq/src/client/http/client/extra.rs +77 -0
- data/vendor/wreq/src/client/http/client/lazy.rs +79 -0
- data/vendor/wreq/src/client/http/client/pool.rs +1105 -0
- data/vendor/wreq/src/client/http/client/util.rs +104 -0
- data/vendor/wreq/src/client/http/client.rs +1003 -0
- data/vendor/wreq/src/client/http/future.rs +99 -0
- data/vendor/wreq/src/client/http.rs +1629 -0
- data/vendor/wreq/src/client/layer/config/options.rs +156 -0
- data/vendor/wreq/src/client/layer/config.rs +116 -0
- data/vendor/wreq/src/client/layer/cookie.rs +161 -0
- data/vendor/wreq/src/client/layer/decoder.rs +139 -0
- data/vendor/wreq/src/client/layer/redirect/future.rs +270 -0
- data/vendor/wreq/src/client/layer/redirect/policy.rs +63 -0
- data/vendor/wreq/src/client/layer/redirect.rs +145 -0
- data/vendor/wreq/src/client/layer/retry/classify.rs +105 -0
- data/vendor/wreq/src/client/layer/retry/scope.rs +51 -0
- data/vendor/wreq/src/client/layer/retry.rs +151 -0
- data/vendor/wreq/src/client/layer/timeout/body.rs +233 -0
- data/vendor/wreq/src/client/layer/timeout/future.rs +90 -0
- data/vendor/wreq/src/client/layer/timeout.rs +177 -0
- data/vendor/wreq/src/client/layer.rs +15 -0
- data/vendor/wreq/src/client/multipart.rs +717 -0
- data/vendor/wreq/src/client/request.rs +818 -0
- data/vendor/wreq/src/client/response.rs +534 -0
- data/vendor/wreq/src/client/ws/json.rs +99 -0
- data/vendor/wreq/src/client/ws/message.rs +453 -0
- data/vendor/wreq/src/client/ws.rs +714 -0
- data/vendor/wreq/src/client.rs +27 -0
- data/vendor/wreq/src/config.rs +140 -0
- data/vendor/wreq/src/cookie.rs +579 -0
- data/vendor/wreq/src/dns/gai.rs +249 -0
- data/vendor/wreq/src/dns/hickory.rs +78 -0
- data/vendor/wreq/src/dns/resolve.rs +180 -0
- data/vendor/wreq/src/dns.rs +69 -0
- data/vendor/wreq/src/error.rs +502 -0
- data/vendor/wreq/src/ext.rs +398 -0
- data/vendor/wreq/src/hash.rs +143 -0
- data/vendor/wreq/src/header.rs +506 -0
- data/vendor/wreq/src/into_uri.rs +187 -0
- data/vendor/wreq/src/lib.rs +586 -0
- data/vendor/wreq/src/proxy/mac.rs +82 -0
- data/vendor/wreq/src/proxy/matcher.rs +806 -0
- data/vendor/wreq/src/proxy/uds.rs +66 -0
- data/vendor/wreq/src/proxy/win.rs +31 -0
- data/vendor/wreq/src/proxy.rs +569 -0
- data/vendor/wreq/src/redirect.rs +575 -0
- data/vendor/wreq/src/retry.rs +198 -0
- data/vendor/wreq/src/sync.rs +129 -0
- data/vendor/wreq/src/tls/conn/cache.rs +123 -0
- data/vendor/wreq/src/tls/conn/cert_compression.rs +125 -0
- data/vendor/wreq/src/tls/conn/ext.rs +82 -0
- data/vendor/wreq/src/tls/conn/macros.rs +34 -0
- data/vendor/wreq/src/tls/conn/service.rs +138 -0
- data/vendor/wreq/src/tls/conn.rs +681 -0
- data/vendor/wreq/src/tls/keylog/handle.rs +64 -0
- data/vendor/wreq/src/tls/keylog.rs +99 -0
- data/vendor/wreq/src/tls/options.rs +464 -0
- data/vendor/wreq/src/tls/x509/identity.rs +122 -0
- data/vendor/wreq/src/tls/x509/parser.rs +71 -0
- data/vendor/wreq/src/tls/x509/store.rs +228 -0
- data/vendor/wreq/src/tls/x509.rs +68 -0
- data/vendor/wreq/src/tls.rs +154 -0
- data/vendor/wreq/src/trace.rs +55 -0
- data/vendor/wreq/src/util.rs +122 -0
- data/vendor/wreq/tests/badssl.rs +228 -0
- data/vendor/wreq/tests/brotli.rs +350 -0
- data/vendor/wreq/tests/client.rs +1098 -0
- data/vendor/wreq/tests/connector_layers.rs +227 -0
- data/vendor/wreq/tests/cookie.rs +306 -0
- data/vendor/wreq/tests/deflate.rs +347 -0
- data/vendor/wreq/tests/emulation.rs +260 -0
- data/vendor/wreq/tests/gzip.rs +347 -0
- data/vendor/wreq/tests/layers.rs +261 -0
- data/vendor/wreq/tests/multipart.rs +165 -0
- data/vendor/wreq/tests/proxy.rs +438 -0
- data/vendor/wreq/tests/redirect.rs +629 -0
- data/vendor/wreq/tests/retry.rs +135 -0
- data/vendor/wreq/tests/support/delay_server.rs +117 -0
- data/vendor/wreq/tests/support/error.rs +16 -0
- data/vendor/wreq/tests/support/layer.rs +183 -0
- data/vendor/wreq/tests/support/mod.rs +9 -0
- data/vendor/wreq/tests/support/server.rs +232 -0
- data/vendor/wreq/tests/timeouts.rs +281 -0
- data/vendor/wreq/tests/unix_socket.rs +135 -0
- data/vendor/wreq/tests/upgrade.rs +98 -0
- data/vendor/wreq/tests/zstd.rs +559 -0
- metadata +225 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
use std::{
|
|
2
|
+
path::{Path, PathBuf},
|
|
3
|
+
sync::Arc,
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
/// Trait for converting various types into a shared Unix Domain Socket path (`Arc<Path>`).
|
|
7
|
+
///
|
|
8
|
+
/// This trait is sealed to allow future extension while controlling which types can implement it.
|
|
9
|
+
/// It enables ergonomic conversion from common path types such as `String`, `&str`, `PathBuf`,
|
|
10
|
+
/// `&Path`, and `Arc<Path>` into a unified `Arc<Path>` representation for Unix socket usage.
|
|
11
|
+
///
|
|
12
|
+
/// # Supported types
|
|
13
|
+
/// - `String`
|
|
14
|
+
/// - `&str`
|
|
15
|
+
/// - `PathBuf`
|
|
16
|
+
/// - `&Path`
|
|
17
|
+
/// - `Arc<Path>`
|
|
18
|
+
pub trait IntoUnixSocket: sealed::Sealed {
|
|
19
|
+
/// Returns the Unix Domain Socket path as an [`Arc<Path>`].
|
|
20
|
+
fn unix_socket(self) -> Arc<Path>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
impl IntoUnixSocket for String {
|
|
24
|
+
fn unix_socket(self) -> Arc<Path> {
|
|
25
|
+
Arc::from(PathBuf::from(self))
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
impl IntoUnixSocket for &'_ str {
|
|
30
|
+
fn unix_socket(self) -> Arc<Path> {
|
|
31
|
+
Arc::from(PathBuf::from(self))
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
impl IntoUnixSocket for &'_ Path {
|
|
36
|
+
fn unix_socket(self) -> Arc<Path> {
|
|
37
|
+
Arc::from(self)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
impl IntoUnixSocket for PathBuf {
|
|
41
|
+
fn unix_socket(self) -> Arc<Path> {
|
|
42
|
+
Arc::from(self)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
impl IntoUnixSocket for Arc<Path> {
|
|
47
|
+
fn unix_socket(self) -> Arc<Path> {
|
|
48
|
+
self
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
mod sealed {
|
|
53
|
+
use std::{
|
|
54
|
+
path::{Path, PathBuf},
|
|
55
|
+
sync::Arc,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/// Sealed trait to prevent external implementations of `IntoUnixSocket`.
|
|
59
|
+
pub trait Sealed {}
|
|
60
|
+
|
|
61
|
+
impl Sealed for String {}
|
|
62
|
+
impl Sealed for &'_ str {}
|
|
63
|
+
impl Sealed for &'_ Path {}
|
|
64
|
+
impl Sealed for PathBuf {}
|
|
65
|
+
impl Sealed for Arc<Path> {}
|
|
66
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
pub(super) fn with_system(builder: &mut super::matcher::Builder) {
|
|
2
|
+
let Ok(settings) = windows_registry::CURRENT_USER
|
|
3
|
+
.open("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings")
|
|
4
|
+
else {
|
|
5
|
+
return;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
if settings.get_u32("ProxyEnable").unwrap_or(0) == 0 {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if let Ok(val) = settings.get_string("ProxyServer") {
|
|
13
|
+
if builder.http.is_empty() {
|
|
14
|
+
builder.http = val.clone();
|
|
15
|
+
}
|
|
16
|
+
if builder.https.is_empty() {
|
|
17
|
+
builder.https = val;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if builder.no.is_empty() {
|
|
22
|
+
if let Ok(val) = settings.get_string("ProxyOverride") {
|
|
23
|
+
builder.no = val
|
|
24
|
+
.split(';')
|
|
25
|
+
.map(|s| s.trim())
|
|
26
|
+
.collect::<Vec<&str>>()
|
|
27
|
+
.join(",")
|
|
28
|
+
.replace("*.", "");
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,569 @@
|
|
|
1
|
+
#[cfg(all(target_os = "macos", feature = "system-proxy"))]
|
|
2
|
+
mod mac;
|
|
3
|
+
#[cfg(unix)]
|
|
4
|
+
mod uds;
|
|
5
|
+
#[cfg(all(windows, feature = "system-proxy"))]
|
|
6
|
+
mod win;
|
|
7
|
+
|
|
8
|
+
pub(crate) mod matcher;
|
|
9
|
+
|
|
10
|
+
use std::hash::{Hash, Hasher};
|
|
11
|
+
#[cfg(unix)]
|
|
12
|
+
use std::{path::Path, sync::Arc};
|
|
13
|
+
|
|
14
|
+
use http::{HeaderMap, Uri, header::HeaderValue};
|
|
15
|
+
|
|
16
|
+
use crate::{IntoUri, ext::UriExt};
|
|
17
|
+
|
|
18
|
+
// # Internals
|
|
19
|
+
//
|
|
20
|
+
// This module is a couple pieces:
|
|
21
|
+
//
|
|
22
|
+
// - The public builder API
|
|
23
|
+
// - The internal built types that our Connector knows how to use.
|
|
24
|
+
//
|
|
25
|
+
// The user creates a builder (`wreq::Proxy`), and configures any extras.
|
|
26
|
+
// Once that type is passed to the `ClientBuilder`, we convert it into the
|
|
27
|
+
// built matcher types, making use of `core`'s matchers.
|
|
28
|
+
|
|
29
|
+
/// Configuration of a proxy that a `Client` should pass requests to.
|
|
30
|
+
///
|
|
31
|
+
/// A `Proxy` has a couple pieces to it:
|
|
32
|
+
///
|
|
33
|
+
/// - a URI of how to talk to the proxy
|
|
34
|
+
/// - rules on what `Client` requests should be directed to the proxy
|
|
35
|
+
///
|
|
36
|
+
/// For instance, let's look at `Proxy::http`:
|
|
37
|
+
///
|
|
38
|
+
/// ```rust
|
|
39
|
+
/// # fn run() -> Result<(), Box<dyn std::error::Error>> {
|
|
40
|
+
/// let proxy = wreq::Proxy::http("https://secure.example")?;
|
|
41
|
+
/// # Ok(())
|
|
42
|
+
/// # }
|
|
43
|
+
/// ```
|
|
44
|
+
///
|
|
45
|
+
/// This proxy will intercept all HTTP requests, and make use of the proxy
|
|
46
|
+
/// at `https://secure.example`. A request to `http://hyper.rs` will talk
|
|
47
|
+
/// to your proxy. A request to `https://hyper.rs` will not.
|
|
48
|
+
///
|
|
49
|
+
/// Multiple `Proxy` rules can be configured for a `Client`. The `Client` will
|
|
50
|
+
/// check each `Proxy` in the order it was added. This could mean that a
|
|
51
|
+
/// `Proxy` added first with eager intercept rules, such as `Proxy::all`,
|
|
52
|
+
/// would prevent a `Proxy` later in the list from ever working, so take care.
|
|
53
|
+
///
|
|
54
|
+
/// By enabling the `"socks"` feature it is possible to use a socks proxy:
|
|
55
|
+
/// ```rust
|
|
56
|
+
/// # fn run() -> Result<(), Box<dyn std::error::Error>> {
|
|
57
|
+
/// let proxy = wreq::Proxy::http("socks5://192.168.1.1:9000")?;
|
|
58
|
+
/// # Ok(())
|
|
59
|
+
/// # }
|
|
60
|
+
/// ```
|
|
61
|
+
#[derive(Clone, Debug)]
|
|
62
|
+
pub struct Proxy {
|
|
63
|
+
extra: Extra,
|
|
64
|
+
scheme: ProxyScheme,
|
|
65
|
+
no_proxy: Option<NoProxy>,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/// A configuration for filtering out requests that shouldn't be proxied
|
|
69
|
+
#[derive(Clone, Debug, Default)]
|
|
70
|
+
pub struct NoProxy {
|
|
71
|
+
inner: String,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ===== Internal =====
|
|
75
|
+
|
|
76
|
+
#[allow(clippy::large_enum_variant)]
|
|
77
|
+
#[derive(Clone, PartialEq, Eq)]
|
|
78
|
+
pub(crate) enum Intercepted {
|
|
79
|
+
Proxy(matcher::Intercept),
|
|
80
|
+
#[cfg(unix)]
|
|
81
|
+
Unix(Arc<Path>),
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
85
|
+
pub(crate) struct Matcher {
|
|
86
|
+
inner: Box<matcher::Matcher>,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
#[derive(Clone, Debug)]
|
|
90
|
+
enum ProxyScheme {
|
|
91
|
+
All(Uri),
|
|
92
|
+
Http(Uri),
|
|
93
|
+
Https(Uri),
|
|
94
|
+
#[cfg(unix)]
|
|
95
|
+
Unix(Arc<Path>),
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
#[derive(Debug, Clone, Default, PartialEq, Eq)]
|
|
99
|
+
struct Extra {
|
|
100
|
+
auth: Option<HeaderValue>,
|
|
101
|
+
misc: Option<HeaderMap>,
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ===== impl Proxy =====
|
|
105
|
+
|
|
106
|
+
impl Proxy {
|
|
107
|
+
/// Proxy all HTTP traffic to the passed URI.
|
|
108
|
+
///
|
|
109
|
+
/// # Example
|
|
110
|
+
///
|
|
111
|
+
/// ```
|
|
112
|
+
/// # extern crate wreq;
|
|
113
|
+
/// # fn run() -> Result<(), Box<dyn std::error::Error>> {
|
|
114
|
+
/// let client = wreq::Client::builder()
|
|
115
|
+
/// .proxy(wreq::Proxy::http("https://my.prox")?)
|
|
116
|
+
/// .build()?;
|
|
117
|
+
/// # Ok(())
|
|
118
|
+
/// # }
|
|
119
|
+
/// # fn main() {}
|
|
120
|
+
/// ```
|
|
121
|
+
pub fn http<U: IntoUri>(uri: U) -> crate::Result<Proxy> {
|
|
122
|
+
uri.into_uri().map(ProxyScheme::Http).map(Proxy::new)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/// Proxy all HTTPS traffic to the passed URI.
|
|
126
|
+
///
|
|
127
|
+
/// # Example
|
|
128
|
+
///
|
|
129
|
+
/// ```
|
|
130
|
+
/// # extern crate wreq;
|
|
131
|
+
/// # fn run() -> Result<(), Box<dyn std::error::Error>> {
|
|
132
|
+
/// let client = wreq::Client::builder()
|
|
133
|
+
/// .proxy(wreq::Proxy::https("https://example.prox:4545")?)
|
|
134
|
+
/// .build()?;
|
|
135
|
+
/// # Ok(())
|
|
136
|
+
/// # }
|
|
137
|
+
/// # fn main() {}
|
|
138
|
+
/// ```
|
|
139
|
+
pub fn https<U: IntoUri>(uri: U) -> crate::Result<Proxy> {
|
|
140
|
+
uri.into_uri().map(ProxyScheme::Https).map(Proxy::new)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/// Proxy **all** traffic to the passed URI.
|
|
144
|
+
///
|
|
145
|
+
/// "All" refers to `https` and `http` URIs. Other schemes are not
|
|
146
|
+
/// recognized by wreq.
|
|
147
|
+
///
|
|
148
|
+
/// # Example
|
|
149
|
+
///
|
|
150
|
+
/// ```
|
|
151
|
+
/// # extern crate wreq;
|
|
152
|
+
/// # fn run() -> Result<(), Box<dyn std::error::Error>> {
|
|
153
|
+
/// let client = wreq::Client::builder()
|
|
154
|
+
/// .proxy(wreq::Proxy::all("http://pro.xy")?)
|
|
155
|
+
/// .build()?;
|
|
156
|
+
/// # Ok(())
|
|
157
|
+
/// # }
|
|
158
|
+
/// # fn main() {}
|
|
159
|
+
/// ```
|
|
160
|
+
pub fn all<U: IntoUri>(uri: U) -> crate::Result<Proxy> {
|
|
161
|
+
uri.into_uri().map(ProxyScheme::All).map(Proxy::new)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/// Proxy all traffic to the passed Unix Domain Socket path.
|
|
165
|
+
///
|
|
166
|
+
/// # Example
|
|
167
|
+
///
|
|
168
|
+
/// ```
|
|
169
|
+
/// # extern crate wreq;
|
|
170
|
+
/// # fn run() -> Result<(), Box<dyn std::error::Error>> {
|
|
171
|
+
/// let client = wreq::Client::builder()
|
|
172
|
+
/// .proxy(wreq::Proxy::unix("/var/run/docker.sock")?)
|
|
173
|
+
/// .build()?;
|
|
174
|
+
/// # Ok(())
|
|
175
|
+
/// # }
|
|
176
|
+
/// # fn main() {}
|
|
177
|
+
/// ```
|
|
178
|
+
#[cfg(unix)]
|
|
179
|
+
pub fn unix<P: uds::IntoUnixSocket>(unix: P) -> crate::Result<Proxy> {
|
|
180
|
+
Ok(Proxy::new(ProxyScheme::Unix(unix.unix_socket())))
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
fn new(scheme: ProxyScheme) -> Proxy {
|
|
184
|
+
Proxy {
|
|
185
|
+
extra: Extra {
|
|
186
|
+
auth: None,
|
|
187
|
+
misc: None,
|
|
188
|
+
},
|
|
189
|
+
scheme,
|
|
190
|
+
no_proxy: None,
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/// Set the `Proxy-Authorization` header using Basic auth.
|
|
195
|
+
///
|
|
196
|
+
/// # Example
|
|
197
|
+
///
|
|
198
|
+
/// ```
|
|
199
|
+
/// # extern crate wreq;
|
|
200
|
+
/// # fn run() -> Result<(), Box<dyn std::error::Error>> {
|
|
201
|
+
/// let proxy = wreq::Proxy::https("http://localhost:1234")?.basic_auth("Aladdin", "open sesame");
|
|
202
|
+
/// # Ok(())
|
|
203
|
+
/// # }
|
|
204
|
+
/// # fn main() {}
|
|
205
|
+
/// ```
|
|
206
|
+
pub fn basic_auth(mut self, username: &str, password: &str) -> Proxy {
|
|
207
|
+
match self.scheme {
|
|
208
|
+
ProxyScheme::All(ref mut uri)
|
|
209
|
+
| ProxyScheme::Http(ref mut uri)
|
|
210
|
+
| ProxyScheme::Https(ref mut uri) => {
|
|
211
|
+
let header = crate::util::basic_auth(username, Some(password));
|
|
212
|
+
uri.set_userinfo(username, Some(password));
|
|
213
|
+
self.extra.auth = Some(header);
|
|
214
|
+
}
|
|
215
|
+
#[cfg(unix)]
|
|
216
|
+
ProxyScheme::Unix(_) => {
|
|
217
|
+
// For Unix sockets, we don't set the auth header.
|
|
218
|
+
// This is a no-op, but keeps the API consistent.
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
self
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/// Set the `Proxy-Authorization` header to a specified value.
|
|
226
|
+
///
|
|
227
|
+
/// # Example
|
|
228
|
+
///
|
|
229
|
+
/// ```
|
|
230
|
+
/// # extern crate wreq;
|
|
231
|
+
/// # use wreq::header::*;
|
|
232
|
+
/// # fn run() -> Result<(), Box<dyn std::error::Error>> {
|
|
233
|
+
/// let proxy = wreq::Proxy::https("http://localhost:1234")?
|
|
234
|
+
/// .custom_http_auth(HeaderValue::from_static("justletmeinalreadyplease"));
|
|
235
|
+
/// # Ok(())
|
|
236
|
+
/// # }
|
|
237
|
+
/// # fn main() {}
|
|
238
|
+
/// ```
|
|
239
|
+
pub fn custom_http_auth(mut self, header_value: HeaderValue) -> Proxy {
|
|
240
|
+
self.extra.auth = Some(header_value);
|
|
241
|
+
self
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/// Adds a Custom Headers to Proxy
|
|
245
|
+
/// Adds custom headers to this Proxy
|
|
246
|
+
///
|
|
247
|
+
/// # Example
|
|
248
|
+
/// ```
|
|
249
|
+
/// # extern crate wreq;
|
|
250
|
+
/// # use wreq::header::*;
|
|
251
|
+
/// # fn run() -> Result<(), Box<dyn std::error::Error>> {
|
|
252
|
+
/// let mut headers = HeaderMap::new();
|
|
253
|
+
/// headers.insert(USER_AGENT, "wreq".parse().unwrap());
|
|
254
|
+
/// let proxy = wreq::Proxy::https("http://localhost:1234")?.custom_http_headers(headers);
|
|
255
|
+
/// # Ok(())
|
|
256
|
+
/// # }
|
|
257
|
+
/// # fn main() {}
|
|
258
|
+
/// ```
|
|
259
|
+
pub fn custom_http_headers(mut self, headers: HeaderMap) -> Proxy {
|
|
260
|
+
match self.scheme {
|
|
261
|
+
ProxyScheme::All(_) | ProxyScheme::Http(_) | ProxyScheme::Https(_) => {
|
|
262
|
+
self.extra.misc = Some(headers);
|
|
263
|
+
}
|
|
264
|
+
#[cfg(unix)]
|
|
265
|
+
ProxyScheme::Unix(_) => {
|
|
266
|
+
// For Unix sockets, we don't set custom headers.
|
|
267
|
+
// This is a no-op, but keeps the API consistent.
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
self
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/// Adds a `No Proxy` exclusion list to this Proxy
|
|
275
|
+
///
|
|
276
|
+
/// # Example
|
|
277
|
+
///
|
|
278
|
+
/// ```
|
|
279
|
+
/// # extern crate wreq;
|
|
280
|
+
/// # fn run() -> Result<(), Box<dyn std::error::Error>> {
|
|
281
|
+
/// let proxy = wreq::Proxy::https("http://localhost:1234")?
|
|
282
|
+
/// .no_proxy(wreq::NoProxy::from_string("direct.tld, sub.direct2.tld"));
|
|
283
|
+
/// # Ok(())
|
|
284
|
+
/// # }
|
|
285
|
+
/// # fn main() {}
|
|
286
|
+
/// ```
|
|
287
|
+
pub fn no_proxy(mut self, no_proxy: Option<NoProxy>) -> Proxy {
|
|
288
|
+
self.no_proxy = no_proxy;
|
|
289
|
+
self
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
pub(crate) fn into_matcher(self) -> Matcher {
|
|
293
|
+
let Proxy {
|
|
294
|
+
scheme,
|
|
295
|
+
extra,
|
|
296
|
+
no_proxy,
|
|
297
|
+
} = self;
|
|
298
|
+
|
|
299
|
+
let no_proxy = no_proxy.as_ref().map_or("", |n| n.inner.as_ref());
|
|
300
|
+
|
|
301
|
+
let inner = match scheme {
|
|
302
|
+
ProxyScheme::All(uri) => matcher::Matcher::builder()
|
|
303
|
+
.all(uri.to_string())
|
|
304
|
+
.no(no_proxy)
|
|
305
|
+
.build(extra),
|
|
306
|
+
ProxyScheme::Http(uri) => matcher::Matcher::builder()
|
|
307
|
+
.http(uri.to_string())
|
|
308
|
+
.no(no_proxy)
|
|
309
|
+
.build(extra),
|
|
310
|
+
ProxyScheme::Https(uri) => matcher::Matcher::builder()
|
|
311
|
+
.https(uri.to_string())
|
|
312
|
+
.no(no_proxy)
|
|
313
|
+
.build(extra),
|
|
314
|
+
#[cfg(unix)]
|
|
315
|
+
ProxyScheme::Unix(unix) => matcher::Matcher::builder()
|
|
316
|
+
.unix(unix)
|
|
317
|
+
.no(no_proxy)
|
|
318
|
+
.build(extra),
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
Matcher {
|
|
322
|
+
inner: Box::new(inner),
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// ===== impl NoProxy =====
|
|
328
|
+
|
|
329
|
+
impl NoProxy {
|
|
330
|
+
/// Returns a new no-proxy configuration based on environment variables (or `None` if no
|
|
331
|
+
/// variables are set) see [self::NoProxy::from_string()] for the string format
|
|
332
|
+
pub fn from_env() -> Option<NoProxy> {
|
|
333
|
+
let raw = std::env::var("NO_PROXY")
|
|
334
|
+
.or_else(|_| std::env::var("no_proxy"))
|
|
335
|
+
.ok()?;
|
|
336
|
+
|
|
337
|
+
// Per the docs, this returns `None` if no environment variable is set. We can only reach
|
|
338
|
+
// here if an env var is set, so we return `Some(NoProxy::default)` if `from_string`
|
|
339
|
+
// returns None, which occurs with an empty string.
|
|
340
|
+
Some(Self::from_string(&raw).unwrap_or_default())
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/// Returns a new no-proxy configuration based on a `no_proxy` string (or `None` if no variables
|
|
344
|
+
/// are set)
|
|
345
|
+
/// The rules are as follows:
|
|
346
|
+
/// * The environment variable `NO_PROXY` is checked, if it is not set, `no_proxy` is checked
|
|
347
|
+
/// * If neither environment variable is set, `None` is returned
|
|
348
|
+
/// * Entries are expected to be comma-separated (whitespace between entries is ignored)
|
|
349
|
+
/// * IP addresses (both IPv4 and IPv6) are allowed, as are optional subnet masks (by adding
|
|
350
|
+
/// /size, for example "`192.168.1.0/24`").
|
|
351
|
+
/// * An entry "`*`" matches all hostnames (this is the only wildcard allowed)
|
|
352
|
+
/// * Any other entry is considered a domain name (and may contain a leading dot, for example
|
|
353
|
+
/// `google.com` and `.google.com` are equivalent) and would match both that domain AND all
|
|
354
|
+
/// subdomains.
|
|
355
|
+
///
|
|
356
|
+
/// For example, if `"NO_PROXY=google.com, 192.168.1.0/24"` was set, all the following would
|
|
357
|
+
/// match (and therefore would bypass the proxy):
|
|
358
|
+
/// * `http://google.com/`
|
|
359
|
+
/// * `http://www.google.com/`
|
|
360
|
+
/// * `http://192.168.1.42/`
|
|
361
|
+
///
|
|
362
|
+
/// The URI `http://notgoogle.com/` would not match.
|
|
363
|
+
pub fn from_string(no_proxy_list: &str) -> Option<Self> {
|
|
364
|
+
Some(NoProxy {
|
|
365
|
+
inner: no_proxy_list.into(),
|
|
366
|
+
})
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// ===== impl Matcher =====
|
|
371
|
+
|
|
372
|
+
impl Matcher {
|
|
373
|
+
pub(crate) fn system() -> Self {
|
|
374
|
+
Self {
|
|
375
|
+
inner: Box::new(matcher::Matcher::from_system()),
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/// Intercept the given destination URI, returning the intercepted
|
|
380
|
+
/// proxy configuration if there is a match.
|
|
381
|
+
#[inline]
|
|
382
|
+
pub(crate) fn intercept(&self, dst: &Uri) -> Option<Intercepted> {
|
|
383
|
+
self.inner.intercept(dst)
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// ===== impl Extra =====
|
|
388
|
+
|
|
389
|
+
impl Hash for Extra {
|
|
390
|
+
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
391
|
+
self.auth.hash(state);
|
|
392
|
+
if let Some(ref misc) = self.misc {
|
|
393
|
+
for (k, v) in misc.iter() {
|
|
394
|
+
k.as_str().hash(state);
|
|
395
|
+
v.as_bytes().hash(state);
|
|
396
|
+
}
|
|
397
|
+
} else {
|
|
398
|
+
1u8.hash(state);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
#[cfg(test)]
|
|
404
|
+
mod tests {
|
|
405
|
+
use super::*;
|
|
406
|
+
|
|
407
|
+
fn uri(s: &str) -> Uri {
|
|
408
|
+
s.parse().unwrap()
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
fn intercept(p: &Matcher, s: &Uri) -> matcher::Intercept {
|
|
412
|
+
match p.intercept(s).unwrap() {
|
|
413
|
+
Intercepted::Proxy(proxy) => proxy,
|
|
414
|
+
#[cfg(unix)]
|
|
415
|
+
_ => {
|
|
416
|
+
unreachable!("intercepted_port should only be called with a Proxy matcher")
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
fn intercepted_uri(p: &Matcher, s: &str) -> Uri {
|
|
422
|
+
match p.intercept(&s.parse().unwrap()).unwrap() {
|
|
423
|
+
Intercepted::Proxy(proxy) => proxy.uri().clone(),
|
|
424
|
+
#[cfg(unix)]
|
|
425
|
+
_ => {
|
|
426
|
+
unreachable!("intercepted_uri should only be called with a Proxy matcher")
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
#[test]
|
|
432
|
+
fn test_http() {
|
|
433
|
+
let target = "http://example.domain/";
|
|
434
|
+
let p = Proxy::http(target).unwrap().into_matcher();
|
|
435
|
+
|
|
436
|
+
let http = "http://hyper.rs";
|
|
437
|
+
let other = "https://hyper.rs";
|
|
438
|
+
|
|
439
|
+
assert_eq!(intercepted_uri(&p, http), target);
|
|
440
|
+
assert!(p.intercept(&uri(other)).is_none());
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
#[test]
|
|
444
|
+
fn test_https() {
|
|
445
|
+
let target = "http://example.domain/";
|
|
446
|
+
let p = Proxy::https(target).unwrap().into_matcher();
|
|
447
|
+
|
|
448
|
+
let http = "http://hyper.rs";
|
|
449
|
+
let other = "https://hyper.rs";
|
|
450
|
+
|
|
451
|
+
assert!(p.intercept(&uri(http)).is_none());
|
|
452
|
+
assert_eq!(intercepted_uri(&p, other), target);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
#[test]
|
|
456
|
+
fn test_all() {
|
|
457
|
+
let target = "http://example.domain/";
|
|
458
|
+
let p = Proxy::all(target).unwrap().into_matcher();
|
|
459
|
+
|
|
460
|
+
let http = "http://hyper.rs";
|
|
461
|
+
let https = "https://hyper.rs";
|
|
462
|
+
// no longer supported
|
|
463
|
+
//let other = "x-youve-never-heard-of-me-mr-proxy://hyper.rs";
|
|
464
|
+
|
|
465
|
+
assert_eq!(intercepted_uri(&p, http), target);
|
|
466
|
+
assert_eq!(intercepted_uri(&p, https), target);
|
|
467
|
+
//assert_eq!(intercepted_uri(&p, other), target);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
#[test]
|
|
471
|
+
fn test_standard_with_custom_auth_header() {
|
|
472
|
+
let target = "http://example.domain/";
|
|
473
|
+
let p = Proxy::all(target)
|
|
474
|
+
.unwrap()
|
|
475
|
+
.custom_http_auth(http::HeaderValue::from_static("testme"))
|
|
476
|
+
.into_matcher();
|
|
477
|
+
|
|
478
|
+
let got = intercept(&p, &uri("http://anywhere.local"));
|
|
479
|
+
let auth = got.basic_auth().unwrap();
|
|
480
|
+
assert_eq!(auth, "testme");
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
#[test]
|
|
484
|
+
fn test_maybe_has_http_auth() {
|
|
485
|
+
let uri = uri("http://example.domain/");
|
|
486
|
+
|
|
487
|
+
let m = Proxy::all("https://letme:in@yo.local")
|
|
488
|
+
.unwrap()
|
|
489
|
+
.into_matcher();
|
|
490
|
+
|
|
491
|
+
let got = intercept(&m, &uri);
|
|
492
|
+
assert!(got.basic_auth().is_some(), "https forwards");
|
|
493
|
+
|
|
494
|
+
let m = Proxy::all("http://letme:in@yo.local")
|
|
495
|
+
.unwrap()
|
|
496
|
+
.into_matcher();
|
|
497
|
+
|
|
498
|
+
let got = intercept(&m, &uri);
|
|
499
|
+
assert!(got.basic_auth().is_some(), "http forwards");
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
#[test]
|
|
503
|
+
fn test_maybe_has_http_custom_headers() {
|
|
504
|
+
let uri = uri("http://example.domain/");
|
|
505
|
+
|
|
506
|
+
let mut headers = HeaderMap::new();
|
|
507
|
+
headers.insert("x-custom-header", HeaderValue::from_static("custom-value"));
|
|
508
|
+
|
|
509
|
+
let m = Proxy::all("https://yo.local")
|
|
510
|
+
.unwrap()
|
|
511
|
+
.custom_http_headers(headers.clone())
|
|
512
|
+
.into_matcher();
|
|
513
|
+
|
|
514
|
+
match m.intercept(&uri).unwrap() {
|
|
515
|
+
Intercepted::Proxy(proxy) => {
|
|
516
|
+
let got_headers = proxy.custom_headers().unwrap();
|
|
517
|
+
assert_eq!(got_headers, &headers, "https forwards");
|
|
518
|
+
}
|
|
519
|
+
#[cfg(unix)]
|
|
520
|
+
_ => {
|
|
521
|
+
unreachable!("Expected a Proxy Intercepted");
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
let m = Proxy::all("http://yo.local")
|
|
526
|
+
.unwrap()
|
|
527
|
+
.custom_http_headers(headers.clone())
|
|
528
|
+
.into_matcher();
|
|
529
|
+
|
|
530
|
+
match m.intercept(&uri).unwrap() {
|
|
531
|
+
Intercepted::Proxy(proxy) => {
|
|
532
|
+
let got_headers = proxy.custom_headers().unwrap();
|
|
533
|
+
assert_eq!(got_headers, &headers, "http forwards");
|
|
534
|
+
}
|
|
535
|
+
#[cfg(unix)]
|
|
536
|
+
_ => {
|
|
537
|
+
unreachable!("Expected a Proxy Intercepted");
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
fn test_socks_proxy_default_port(uri: &str, url2: &str, port: u16) {
|
|
543
|
+
let m = Proxy::all(uri).unwrap().into_matcher();
|
|
544
|
+
|
|
545
|
+
let http = "http://hyper.rs";
|
|
546
|
+
let https = "https://hyper.rs";
|
|
547
|
+
|
|
548
|
+
assert_eq!(intercepted_uri(&m, http).port_u16(), Some(1080));
|
|
549
|
+
assert_eq!(intercepted_uri(&m, https).port_u16(), Some(1080));
|
|
550
|
+
|
|
551
|
+
// custom port
|
|
552
|
+
let m = Proxy::all(url2).unwrap().into_matcher();
|
|
553
|
+
|
|
554
|
+
assert_eq!(intercepted_uri(&m, http).port_u16(), Some(port));
|
|
555
|
+
assert_eq!(intercepted_uri(&m, https).port_u16(), Some(port));
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
#[test]
|
|
559
|
+
fn test_socks4_proxy_default_port() {
|
|
560
|
+
test_socks_proxy_default_port("socks4://example.com", "socks4://example.com:1234", 1234);
|
|
561
|
+
test_socks_proxy_default_port("socks4a://example.com", "socks4a://example.com:1234", 1234);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
#[test]
|
|
565
|
+
fn test_socks5_proxy_default_port() {
|
|
566
|
+
test_socks_proxy_default_port("socks5://example.com", "socks5://example.com:1234", 1234);
|
|
567
|
+
test_socks_proxy_default_port("socks5h://example.com", "socks5h://example.com:1234", 1234);
|
|
568
|
+
}
|
|
569
|
+
}
|