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,156 @@
|
|
|
1
|
+
use http::Version;
|
|
2
|
+
|
|
3
|
+
use crate::{
|
|
4
|
+
client::{
|
|
5
|
+
conn::TcpConnectOptions,
|
|
6
|
+
core::{http1::Http1Options, http2::Http2Options},
|
|
7
|
+
},
|
|
8
|
+
proxy::Matcher,
|
|
9
|
+
tls::TlsOptions,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/// Per-request configuration for proxy, protocol, and transport options.
|
|
13
|
+
/// Overrides client defaults for a single request.
|
|
14
|
+
#[derive(Debug, Default, Clone, Hash, PartialEq, Eq)]
|
|
15
|
+
#[non_exhaustive]
|
|
16
|
+
pub struct RequestOptions {
|
|
17
|
+
proxy_matcher: Option<Matcher>,
|
|
18
|
+
enforced_version: Option<Version>,
|
|
19
|
+
tcp_connect_opts: TcpConnectOptions,
|
|
20
|
+
transport_opts: TransportOptions,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/// Transport options for HTTP/1, HTTP/2, and TLS layers.
|
|
24
|
+
///
|
|
25
|
+
/// This struct allows you to customize protocol-specific and TLS settings
|
|
26
|
+
/// for network connections made by the client.
|
|
27
|
+
#[derive(Debug, Default, Clone, Hash, PartialEq, Eq)]
|
|
28
|
+
#[non_exhaustive]
|
|
29
|
+
pub struct TransportOptions {
|
|
30
|
+
tls_options: Option<TlsOptions>,
|
|
31
|
+
http1_options: Option<Http1Options>,
|
|
32
|
+
http2_options: Option<Http2Options>,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ===== impl RequestOptions =====
|
|
36
|
+
|
|
37
|
+
impl_request_config_value!(RequestOptions);
|
|
38
|
+
|
|
39
|
+
// ===== impl TransportOptions =====
|
|
40
|
+
|
|
41
|
+
impl TransportOptions {
|
|
42
|
+
/// Get the reference to the TLS options.
|
|
43
|
+
#[inline]
|
|
44
|
+
pub fn tls_options(&self) -> Option<&TlsOptions> {
|
|
45
|
+
self.tls_options.as_ref()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/// Get a mutable reference to the TLS options.
|
|
49
|
+
#[inline]
|
|
50
|
+
pub fn tls_options_mut(&mut self) -> &mut Option<TlsOptions> {
|
|
51
|
+
&mut self.tls_options
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/// Get the reference to the HTTP/1 options.
|
|
55
|
+
#[inline]
|
|
56
|
+
pub fn http1_options(&self) -> Option<&Http1Options> {
|
|
57
|
+
self.http1_options.as_ref()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/// Get a mutable reference to the HTTP/1 options.
|
|
61
|
+
#[inline]
|
|
62
|
+
pub fn http1_options_mut(&mut self) -> &mut Option<Http1Options> {
|
|
63
|
+
&mut self.http1_options
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/// Get the reference to the HTTP/2 options.
|
|
67
|
+
#[inline]
|
|
68
|
+
pub fn http2_options(&self) -> Option<&Http2Options> {
|
|
69
|
+
self.http2_options.as_ref()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/// Get a mutable reference to the HTTP/2 options.
|
|
73
|
+
#[inline]
|
|
74
|
+
pub fn http2_options_mut(&mut self) -> &mut Option<Http2Options> {
|
|
75
|
+
&mut self.http2_options
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/// Apply the transport options for HTTP/1, HTTP/2, and TLS.
|
|
79
|
+
pub(crate) fn apply_transport_options(&mut self, opts: TransportOptions) -> &mut Self {
|
|
80
|
+
if let Some(tls) = opts.tls_options {
|
|
81
|
+
*self.tls_options_mut() = Some(tls);
|
|
82
|
+
}
|
|
83
|
+
if let Some(http1) = opts.http1_options {
|
|
84
|
+
*self.http1_options_mut() = Some(http1);
|
|
85
|
+
}
|
|
86
|
+
if let Some(http2) = opts.http2_options {
|
|
87
|
+
*self.http2_options_mut() = Some(http2);
|
|
88
|
+
}
|
|
89
|
+
self
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
impl From<TransportOptions>
|
|
94
|
+
for (
|
|
95
|
+
Option<TlsOptions>,
|
|
96
|
+
Option<Http1Options>,
|
|
97
|
+
Option<Http2Options>,
|
|
98
|
+
)
|
|
99
|
+
{
|
|
100
|
+
#[inline]
|
|
101
|
+
fn from(value: TransportOptions) -> Self {
|
|
102
|
+
(value.tls_options, value.http1_options, value.http2_options)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ===== impl RequestOptions =====
|
|
107
|
+
|
|
108
|
+
impl RequestOptions {
|
|
109
|
+
/// Get a reference to the proxy matcher.
|
|
110
|
+
#[inline]
|
|
111
|
+
pub fn proxy_matcher(&self) -> Option<&Matcher> {
|
|
112
|
+
self.proxy_matcher.as_ref()
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/// Get a mutable reference to the proxy matcher.
|
|
116
|
+
#[inline]
|
|
117
|
+
pub fn proxy_matcher_mut(&mut self) -> &mut Option<Matcher> {
|
|
118
|
+
&mut self.proxy_matcher
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/// Get the enforced HTTP version.
|
|
122
|
+
#[inline]
|
|
123
|
+
pub fn enforced_version(&self) -> Option<Version> {
|
|
124
|
+
self.enforced_version
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/// Get a mutable reference to the enforced HTTP version.
|
|
128
|
+
#[inline]
|
|
129
|
+
pub fn enforced_version_mut(&mut self) -> &mut Option<Version> {
|
|
130
|
+
&mut self.enforced_version
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/// Get a reference to the TCP connection options.
|
|
134
|
+
#[inline]
|
|
135
|
+
pub fn tcp_connect_opts(&self) -> &TcpConnectOptions {
|
|
136
|
+
&self.tcp_connect_opts
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/// Get a mutable reference to the TCP connection options.
|
|
140
|
+
#[inline]
|
|
141
|
+
pub fn tcp_connect_opts_mut(&mut self) -> &mut TcpConnectOptions {
|
|
142
|
+
&mut self.tcp_connect_opts
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/// Get a reference to the transport options.
|
|
146
|
+
#[inline]
|
|
147
|
+
pub fn transport_opts(&self) -> &TransportOptions {
|
|
148
|
+
&self.transport_opts
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/// Get a mutable reference to the transport options.
|
|
152
|
+
#[inline]
|
|
153
|
+
pub fn transport_opts_mut(&mut self) -> &mut TransportOptions {
|
|
154
|
+
&mut self.transport_opts
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
mod options;
|
|
2
|
+
|
|
3
|
+
use std::{
|
|
4
|
+
sync::Arc,
|
|
5
|
+
task::{Context, Poll},
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
use futures_util::future::{self, Either, Ready};
|
|
9
|
+
use http::{HeaderMap, Request, Response};
|
|
10
|
+
use tower::{Layer, Service};
|
|
11
|
+
|
|
12
|
+
pub use self::options::{RequestOptions, TransportOptions};
|
|
13
|
+
use crate::{Error, config::RequestConfig, ext::UriExt, header::OrigHeaderMap};
|
|
14
|
+
|
|
15
|
+
/// A marker type for the default headers configuration value.
|
|
16
|
+
#[derive(Clone, Copy)]
|
|
17
|
+
pub(crate) struct DefaultHeaders;
|
|
18
|
+
|
|
19
|
+
/// Configuration for the [`ConfigService`].
|
|
20
|
+
struct Config {
|
|
21
|
+
https_only: bool,
|
|
22
|
+
headers: HeaderMap,
|
|
23
|
+
orig_headers: RequestConfig<OrigHeaderMap>,
|
|
24
|
+
default_headers: RequestConfig<DefaultHeaders>,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/// Middleware layer to use [`ConfigService`].
|
|
28
|
+
pub struct ConfigServiceLayer {
|
|
29
|
+
config: Arc<Config>,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// Middleware service to use [`Config`].
|
|
33
|
+
#[derive(Clone)]
|
|
34
|
+
pub struct ConfigService<S> {
|
|
35
|
+
inner: S,
|
|
36
|
+
config: Arc<Config>,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ===== impl DefaultHeaders =====
|
|
40
|
+
|
|
41
|
+
impl_request_config_value!(DefaultHeaders, bool);
|
|
42
|
+
|
|
43
|
+
// ===== impl ConfigServiceLayer =====
|
|
44
|
+
|
|
45
|
+
impl ConfigServiceLayer {
|
|
46
|
+
/// Creates a new [`ConfigServiceLayer`].
|
|
47
|
+
pub fn new(https_only: bool, headers: HeaderMap, orig_headers: OrigHeaderMap) -> Self {
|
|
48
|
+
let org_headers = (!orig_headers.is_empty()).then_some(orig_headers);
|
|
49
|
+
ConfigServiceLayer {
|
|
50
|
+
config: Arc::new(Config {
|
|
51
|
+
https_only,
|
|
52
|
+
headers,
|
|
53
|
+
orig_headers: RequestConfig::new(org_headers),
|
|
54
|
+
default_headers: RequestConfig::new(Some(true)),
|
|
55
|
+
}),
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
impl<S> Layer<S> for ConfigServiceLayer {
|
|
61
|
+
type Service = ConfigService<S>;
|
|
62
|
+
|
|
63
|
+
#[inline(always)]
|
|
64
|
+
fn layer(&self, inner: S) -> Self::Service {
|
|
65
|
+
ConfigService {
|
|
66
|
+
inner,
|
|
67
|
+
config: self.config.clone(),
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ===== impl ConfigService =====
|
|
73
|
+
|
|
74
|
+
impl<ReqBody, ResBody, S> Service<Request<ReqBody>> for ConfigService<S>
|
|
75
|
+
where
|
|
76
|
+
S: Service<Request<ReqBody>, Response = Response<ResBody>>,
|
|
77
|
+
S::Error: From<Error>,
|
|
78
|
+
{
|
|
79
|
+
type Response = S::Response;
|
|
80
|
+
type Error = S::Error;
|
|
81
|
+
type Future = Either<S::Future, Ready<Result<Self::Response, Self::Error>>>;
|
|
82
|
+
|
|
83
|
+
#[inline(always)]
|
|
84
|
+
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
85
|
+
self.inner.poll_ready(cx)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
fn call(&mut self, mut req: Request<ReqBody>) -> Self::Future {
|
|
89
|
+
let uri = req.uri().clone();
|
|
90
|
+
|
|
91
|
+
// check if the request URI scheme is valid.
|
|
92
|
+
if !(uri.is_http() || uri.is_https()) || (self.config.https_only && !uri.is_https()) {
|
|
93
|
+
return Either::Right(future::err(Error::uri_bad_scheme(uri.clone()).into()));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// check if the request ignores the default headers.
|
|
97
|
+
if self
|
|
98
|
+
.config
|
|
99
|
+
.default_headers
|
|
100
|
+
.fetch(req.extensions())
|
|
101
|
+
.copied()
|
|
102
|
+
.unwrap_or_default()
|
|
103
|
+
{
|
|
104
|
+
// insert default headers in the request headers
|
|
105
|
+
// without overwriting already appended headers.
|
|
106
|
+
let mut dest = self.config.headers.clone();
|
|
107
|
+
crate::util::replace_headers(&mut dest, std::mem::take(req.headers_mut()));
|
|
108
|
+
std::mem::swap(req.headers_mut(), &mut dest);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// store the original headers in request extensions
|
|
112
|
+
self.config.orig_headers.store(req.extensions_mut());
|
|
113
|
+
|
|
114
|
+
Either::Left(self.inner.call(req))
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
//! Middleware to use Cookie.
|
|
2
|
+
|
|
3
|
+
use std::{
|
|
4
|
+
future::Future,
|
|
5
|
+
pin::Pin,
|
|
6
|
+
sync::Arc,
|
|
7
|
+
task::{Context, Poll, ready},
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
use http::{Request, Response, Uri, header::COOKIE};
|
|
11
|
+
use pin_project_lite::pin_project;
|
|
12
|
+
use tower::{Layer, Service};
|
|
13
|
+
|
|
14
|
+
use crate::{
|
|
15
|
+
config::RequestConfig,
|
|
16
|
+
cookie::{CookieStore, Cookies},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
pin_project! {
|
|
20
|
+
/// Response future for [`CookieService`].
|
|
21
|
+
#[project = ResponseFutureProj]
|
|
22
|
+
pub enum ResponseFuture<Fut> {
|
|
23
|
+
Managed {
|
|
24
|
+
#[pin]
|
|
25
|
+
fut: Fut,
|
|
26
|
+
uri: Uri,
|
|
27
|
+
store: Arc<dyn CookieStore>,
|
|
28
|
+
},
|
|
29
|
+
Plain {
|
|
30
|
+
#[pin]
|
|
31
|
+
fut: Fut,
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/// Layer to apply [`CookieService`] middleware.
|
|
37
|
+
#[derive(Clone)]
|
|
38
|
+
pub struct CookieServiceLayer {
|
|
39
|
+
store: RequestConfig<Arc<dyn CookieStore>>,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// Middleware to use [`CookieStore`].
|
|
43
|
+
#[derive(Clone)]
|
|
44
|
+
pub struct CookieService<S> {
|
|
45
|
+
inner: S,
|
|
46
|
+
store: RequestConfig<Arc<dyn CookieStore>>,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ===== impl ResponseFuture =====
|
|
50
|
+
|
|
51
|
+
impl<F, ResBody, E> Future for ResponseFuture<F>
|
|
52
|
+
where
|
|
53
|
+
F: Future<Output = Result<Response<ResBody>, E>>,
|
|
54
|
+
{
|
|
55
|
+
type Output = F::Output;
|
|
56
|
+
|
|
57
|
+
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
58
|
+
match self.project() {
|
|
59
|
+
ResponseFutureProj::Managed { fut, uri, store } => {
|
|
60
|
+
let res = ready!(fut.poll(cx)?);
|
|
61
|
+
let mut cookies = res
|
|
62
|
+
.headers()
|
|
63
|
+
.get_all(http::header::SET_COOKIE)
|
|
64
|
+
.iter()
|
|
65
|
+
.peekable();
|
|
66
|
+
if cookies.peek().is_some() {
|
|
67
|
+
store.set_cookies(&mut cookies, uri);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
Poll::Ready(Ok(res))
|
|
71
|
+
}
|
|
72
|
+
ResponseFutureProj::Plain { fut: mut future } => future.as_mut().poll(cx),
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ===== impl CookieServiceLayer =====
|
|
78
|
+
|
|
79
|
+
impl CookieServiceLayer {
|
|
80
|
+
/// Create a new [`CookieServiceLayer`].
|
|
81
|
+
#[inline(always)]
|
|
82
|
+
pub const fn new(store: Option<Arc<dyn CookieStore + 'static>>) -> Self {
|
|
83
|
+
Self {
|
|
84
|
+
store: RequestConfig::new(store),
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
impl<S> Layer<S> for CookieServiceLayer {
|
|
90
|
+
type Service = CookieService<S>;
|
|
91
|
+
|
|
92
|
+
#[inline(always)]
|
|
93
|
+
fn layer(&self, inner: S) -> Self::Service {
|
|
94
|
+
CookieService {
|
|
95
|
+
inner,
|
|
96
|
+
store: self.store.clone(),
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ===== impl CookieService =====
|
|
102
|
+
|
|
103
|
+
impl<S> CookieService<S> {
|
|
104
|
+
fn inject_cookies<B>(
|
|
105
|
+
&self,
|
|
106
|
+
req: &mut Request<B>,
|
|
107
|
+
store: Arc<dyn CookieStore>,
|
|
108
|
+
) -> (Arc<dyn CookieStore>, Uri) {
|
|
109
|
+
let uri = req.uri().clone();
|
|
110
|
+
let headers = req.headers_mut();
|
|
111
|
+
|
|
112
|
+
// Only inject cookies if request doesn't already have them
|
|
113
|
+
if !headers.contains_key(COOKIE) {
|
|
114
|
+
match store.cookies(&uri) {
|
|
115
|
+
Cookies::Compressed(value) => {
|
|
116
|
+
headers.insert(COOKIE, value);
|
|
117
|
+
}
|
|
118
|
+
Cookies::Uncompressed(values) => {
|
|
119
|
+
for value in values {
|
|
120
|
+
headers.append(COOKIE, value);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
Cookies::Empty => (),
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
(store, uri)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
impl<ReqBody, ResBody, S> Service<Request<ReqBody>> for CookieService<S>
|
|
132
|
+
where
|
|
133
|
+
S: Service<Request<ReqBody>, Response = Response<ResBody>>,
|
|
134
|
+
{
|
|
135
|
+
type Response = S::Response;
|
|
136
|
+
type Error = S::Error;
|
|
137
|
+
type Future = ResponseFuture<S::Future>;
|
|
138
|
+
|
|
139
|
+
#[inline(always)]
|
|
140
|
+
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
141
|
+
self.inner.poll_ready(cx)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
fn call(&mut self, mut req: Request<ReqBody>) -> Self::Future {
|
|
145
|
+
match self
|
|
146
|
+
.store
|
|
147
|
+
.fetch(req.extensions())
|
|
148
|
+
.cloned()
|
|
149
|
+
.map(|store| self.inject_cookies(&mut req, store))
|
|
150
|
+
{
|
|
151
|
+
Some((store, uri)) => ResponseFuture::Managed {
|
|
152
|
+
uri,
|
|
153
|
+
store,
|
|
154
|
+
fut: self.inner.call(req),
|
|
155
|
+
},
|
|
156
|
+
None => ResponseFuture::Plain {
|
|
157
|
+
fut: self.inner.call(req),
|
|
158
|
+
},
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
//! Middleware for decoding
|
|
2
|
+
|
|
3
|
+
use std::task::{Context, Poll};
|
|
4
|
+
|
|
5
|
+
use http::{Request, Response};
|
|
6
|
+
use http_body::Body;
|
|
7
|
+
use tower::{Layer, Service};
|
|
8
|
+
use tower_http::decompression::{self, DecompressionBody, ResponseFuture};
|
|
9
|
+
|
|
10
|
+
use crate::config::RequestConfig;
|
|
11
|
+
|
|
12
|
+
/// Configuration for supported content-encoding algorithms.
|
|
13
|
+
///
|
|
14
|
+
/// `AcceptEncoding` controls which compression formats are enabled for decoding
|
|
15
|
+
/// response bodies. Each field corresponds to a specific algorithm and is only
|
|
16
|
+
/// available if the corresponding feature is enabled.
|
|
17
|
+
#[derive(Clone)]
|
|
18
|
+
pub(crate) struct AcceptEncoding {
|
|
19
|
+
#[cfg(feature = "gzip")]
|
|
20
|
+
pub(crate) gzip: bool,
|
|
21
|
+
#[cfg(feature = "brotli")]
|
|
22
|
+
pub(crate) brotli: bool,
|
|
23
|
+
#[cfg(feature = "zstd")]
|
|
24
|
+
pub(crate) zstd: bool,
|
|
25
|
+
#[cfg(feature = "deflate")]
|
|
26
|
+
pub(crate) deflate: bool,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/// Layer that adds response body decompression to a service.
|
|
30
|
+
#[derive(Clone)]
|
|
31
|
+
pub struct DecompressionLayer {
|
|
32
|
+
accept: AcceptEncoding,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// Service that decompresses response bodies based on the [`AcceptEncoding`] configuration.
|
|
36
|
+
#[derive(Clone)]
|
|
37
|
+
pub struct Decompression<S>(Option<decompression::Decompression<S>>);
|
|
38
|
+
|
|
39
|
+
// ===== AcceptEncoding =====
|
|
40
|
+
|
|
41
|
+
impl Default for AcceptEncoding {
|
|
42
|
+
fn default() -> AcceptEncoding {
|
|
43
|
+
AcceptEncoding {
|
|
44
|
+
#[cfg(feature = "gzip")]
|
|
45
|
+
gzip: true,
|
|
46
|
+
#[cfg(feature = "brotli")]
|
|
47
|
+
brotli: true,
|
|
48
|
+
#[cfg(feature = "zstd")]
|
|
49
|
+
zstd: true,
|
|
50
|
+
#[cfg(feature = "deflate")]
|
|
51
|
+
deflate: true,
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
impl_request_config_value!(AcceptEncoding);
|
|
57
|
+
|
|
58
|
+
// ===== impl DecompressionLayer =====
|
|
59
|
+
|
|
60
|
+
impl DecompressionLayer {
|
|
61
|
+
/// Creates a new [`DecompressionLayer`] with the specified [`AcceptEncoding`].
|
|
62
|
+
#[inline(always)]
|
|
63
|
+
pub const fn new(accept: AcceptEncoding) -> Self {
|
|
64
|
+
Self { accept }
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
impl<S> Layer<S> for DecompressionLayer {
|
|
69
|
+
type Service = Decompression<S>;
|
|
70
|
+
|
|
71
|
+
#[inline(always)]
|
|
72
|
+
fn layer(&self, service: S) -> Self::Service {
|
|
73
|
+
Decompression(Some(Decompression::<S>::accept_in_place(
|
|
74
|
+
decompression::Decompression::new(service),
|
|
75
|
+
&self.accept,
|
|
76
|
+
)))
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ===== impl Decompression =====
|
|
81
|
+
|
|
82
|
+
impl<S> Decompression<S> {
|
|
83
|
+
const BUG_MSG: &str = "[BUG] Decompression service not initialized; bug in setup";
|
|
84
|
+
|
|
85
|
+
fn accept_in_place(
|
|
86
|
+
mut decoder: decompression::Decompression<S>,
|
|
87
|
+
accept: &AcceptEncoding,
|
|
88
|
+
) -> decompression::Decompression<S> {
|
|
89
|
+
#[cfg(feature = "gzip")]
|
|
90
|
+
{
|
|
91
|
+
decoder = decoder.gzip(accept.gzip);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
#[cfg(feature = "deflate")]
|
|
95
|
+
{
|
|
96
|
+
decoder = decoder.deflate(accept.deflate);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
#[cfg(feature = "brotli")]
|
|
100
|
+
{
|
|
101
|
+
decoder = decoder.br(accept.brotli);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
#[cfg(feature = "zstd")]
|
|
105
|
+
{
|
|
106
|
+
decoder = decoder.zstd(accept.zstd);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
decoder
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
impl<S, ReqBody, ResBody> Service<Request<ReqBody>> for Decompression<S>
|
|
114
|
+
where
|
|
115
|
+
S: Service<Request<ReqBody>, Response = Response<ResBody>>,
|
|
116
|
+
ReqBody: Body,
|
|
117
|
+
ResBody: Body,
|
|
118
|
+
{
|
|
119
|
+
type Response = Response<DecompressionBody<ResBody>>;
|
|
120
|
+
type Error = S::Error;
|
|
121
|
+
type Future = ResponseFuture<S::Future>;
|
|
122
|
+
|
|
123
|
+
#[inline(always)]
|
|
124
|
+
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
125
|
+
self.0.as_mut().expect(Self::BUG_MSG).poll_ready(cx)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
|
|
129
|
+
if let Some(accept) = RequestConfig::<AcceptEncoding>::get(req.extensions()) {
|
|
130
|
+
if let Some(decoder) = self.0.take() {
|
|
131
|
+
self.0
|
|
132
|
+
.replace(Decompression::accept_in_place(decoder, accept));
|
|
133
|
+
}
|
|
134
|
+
debug_assert!(self.0.is_some());
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
self.0.as_mut().expect(Self::BUG_MSG).call(req)
|
|
138
|
+
}
|
|
139
|
+
}
|