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.
Files changed (167) hide show
  1. checksums.yaml +7 -0
  2. data/Cargo.lock +2688 -0
  3. data/Cargo.toml +6 -0
  4. data/README.md +179 -0
  5. data/ext/wreq_rb/Cargo.toml +39 -0
  6. data/ext/wreq_rb/extconf.rb +22 -0
  7. data/ext/wreq_rb/src/client.rs +565 -0
  8. data/ext/wreq_rb/src/error.rs +25 -0
  9. data/ext/wreq_rb/src/lib.rs +20 -0
  10. data/ext/wreq_rb/src/response.rs +132 -0
  11. data/lib/wreq-rb/version.rb +5 -0
  12. data/lib/wreq-rb.rb +17 -0
  13. data/patches/0001-add-transfer-size-tracking.patch +292 -0
  14. data/vendor/wreq/Cargo.toml +306 -0
  15. data/vendor/wreq/LICENSE +202 -0
  16. data/vendor/wreq/README.md +122 -0
  17. data/vendor/wreq/examples/cert_store.rs +77 -0
  18. data/vendor/wreq/examples/connect_via_lower_priority_tokio_runtime.rs +258 -0
  19. data/vendor/wreq/examples/emulation.rs +118 -0
  20. data/vendor/wreq/examples/form.rs +14 -0
  21. data/vendor/wreq/examples/http1_websocket.rs +37 -0
  22. data/vendor/wreq/examples/http2_websocket.rs +45 -0
  23. data/vendor/wreq/examples/json_dynamic.rs +41 -0
  24. data/vendor/wreq/examples/json_typed.rs +47 -0
  25. data/vendor/wreq/examples/keylog.rs +16 -0
  26. data/vendor/wreq/examples/request_with_emulation.rs +115 -0
  27. data/vendor/wreq/examples/request_with_interface.rs +37 -0
  28. data/vendor/wreq/examples/request_with_local_address.rs +16 -0
  29. data/vendor/wreq/examples/request_with_proxy.rs +13 -0
  30. data/vendor/wreq/examples/request_with_redirect.rs +22 -0
  31. data/vendor/wreq/examples/request_with_version.rs +15 -0
  32. data/vendor/wreq/examples/tor_socks.rs +24 -0
  33. data/vendor/wreq/examples/unix_socket.rs +33 -0
  34. data/vendor/wreq/src/client/body.rs +304 -0
  35. data/vendor/wreq/src/client/conn/conn.rs +231 -0
  36. data/vendor/wreq/src/client/conn/connector.rs +549 -0
  37. data/vendor/wreq/src/client/conn/http.rs +1023 -0
  38. data/vendor/wreq/src/client/conn/proxy/socks.rs +233 -0
  39. data/vendor/wreq/src/client/conn/proxy/tunnel.rs +260 -0
  40. data/vendor/wreq/src/client/conn/proxy.rs +39 -0
  41. data/vendor/wreq/src/client/conn/tls_info.rs +98 -0
  42. data/vendor/wreq/src/client/conn/uds.rs +44 -0
  43. data/vendor/wreq/src/client/conn/verbose.rs +149 -0
  44. data/vendor/wreq/src/client/conn.rs +323 -0
  45. data/vendor/wreq/src/client/core/body/incoming.rs +485 -0
  46. data/vendor/wreq/src/client/core/body/length.rs +118 -0
  47. data/vendor/wreq/src/client/core/body.rs +34 -0
  48. data/vendor/wreq/src/client/core/common/buf.rs +149 -0
  49. data/vendor/wreq/src/client/core/common/rewind.rs +141 -0
  50. data/vendor/wreq/src/client/core/common/watch.rs +76 -0
  51. data/vendor/wreq/src/client/core/common.rs +3 -0
  52. data/vendor/wreq/src/client/core/conn/http1.rs +342 -0
  53. data/vendor/wreq/src/client/core/conn/http2.rs +307 -0
  54. data/vendor/wreq/src/client/core/conn.rs +11 -0
  55. data/vendor/wreq/src/client/core/dispatch.rs +299 -0
  56. data/vendor/wreq/src/client/core/error.rs +435 -0
  57. data/vendor/wreq/src/client/core/ext.rs +201 -0
  58. data/vendor/wreq/src/client/core/http1.rs +178 -0
  59. data/vendor/wreq/src/client/core/http2.rs +483 -0
  60. data/vendor/wreq/src/client/core/proto/h1/conn.rs +988 -0
  61. data/vendor/wreq/src/client/core/proto/h1/decode.rs +1170 -0
  62. data/vendor/wreq/src/client/core/proto/h1/dispatch.rs +684 -0
  63. data/vendor/wreq/src/client/core/proto/h1/encode.rs +580 -0
  64. data/vendor/wreq/src/client/core/proto/h1/io.rs +879 -0
  65. data/vendor/wreq/src/client/core/proto/h1/role.rs +694 -0
  66. data/vendor/wreq/src/client/core/proto/h1.rs +104 -0
  67. data/vendor/wreq/src/client/core/proto/h2/client.rs +650 -0
  68. data/vendor/wreq/src/client/core/proto/h2/ping.rs +539 -0
  69. data/vendor/wreq/src/client/core/proto/h2.rs +379 -0
  70. data/vendor/wreq/src/client/core/proto/headers.rs +138 -0
  71. data/vendor/wreq/src/client/core/proto.rs +58 -0
  72. data/vendor/wreq/src/client/core/rt/bounds.rs +57 -0
  73. data/vendor/wreq/src/client/core/rt/timer.rs +150 -0
  74. data/vendor/wreq/src/client/core/rt/tokio.rs +99 -0
  75. data/vendor/wreq/src/client/core/rt.rs +25 -0
  76. data/vendor/wreq/src/client/core/upgrade.rs +267 -0
  77. data/vendor/wreq/src/client/core.rs +16 -0
  78. data/vendor/wreq/src/client/emulation.rs +161 -0
  79. data/vendor/wreq/src/client/http/client/error.rs +142 -0
  80. data/vendor/wreq/src/client/http/client/exec.rs +29 -0
  81. data/vendor/wreq/src/client/http/client/extra.rs +77 -0
  82. data/vendor/wreq/src/client/http/client/lazy.rs +79 -0
  83. data/vendor/wreq/src/client/http/client/pool.rs +1105 -0
  84. data/vendor/wreq/src/client/http/client/util.rs +104 -0
  85. data/vendor/wreq/src/client/http/client.rs +1003 -0
  86. data/vendor/wreq/src/client/http/future.rs +99 -0
  87. data/vendor/wreq/src/client/http.rs +1629 -0
  88. data/vendor/wreq/src/client/layer/config/options.rs +156 -0
  89. data/vendor/wreq/src/client/layer/config.rs +116 -0
  90. data/vendor/wreq/src/client/layer/cookie.rs +161 -0
  91. data/vendor/wreq/src/client/layer/decoder.rs +139 -0
  92. data/vendor/wreq/src/client/layer/redirect/future.rs +270 -0
  93. data/vendor/wreq/src/client/layer/redirect/policy.rs +63 -0
  94. data/vendor/wreq/src/client/layer/redirect.rs +145 -0
  95. data/vendor/wreq/src/client/layer/retry/classify.rs +105 -0
  96. data/vendor/wreq/src/client/layer/retry/scope.rs +51 -0
  97. data/vendor/wreq/src/client/layer/retry.rs +151 -0
  98. data/vendor/wreq/src/client/layer/timeout/body.rs +233 -0
  99. data/vendor/wreq/src/client/layer/timeout/future.rs +90 -0
  100. data/vendor/wreq/src/client/layer/timeout.rs +177 -0
  101. data/vendor/wreq/src/client/layer.rs +15 -0
  102. data/vendor/wreq/src/client/multipart.rs +717 -0
  103. data/vendor/wreq/src/client/request.rs +818 -0
  104. data/vendor/wreq/src/client/response.rs +534 -0
  105. data/vendor/wreq/src/client/ws/json.rs +99 -0
  106. data/vendor/wreq/src/client/ws/message.rs +453 -0
  107. data/vendor/wreq/src/client/ws.rs +714 -0
  108. data/vendor/wreq/src/client.rs +27 -0
  109. data/vendor/wreq/src/config.rs +140 -0
  110. data/vendor/wreq/src/cookie.rs +579 -0
  111. data/vendor/wreq/src/dns/gai.rs +249 -0
  112. data/vendor/wreq/src/dns/hickory.rs +78 -0
  113. data/vendor/wreq/src/dns/resolve.rs +180 -0
  114. data/vendor/wreq/src/dns.rs +69 -0
  115. data/vendor/wreq/src/error.rs +502 -0
  116. data/vendor/wreq/src/ext.rs +398 -0
  117. data/vendor/wreq/src/hash.rs +143 -0
  118. data/vendor/wreq/src/header.rs +506 -0
  119. data/vendor/wreq/src/into_uri.rs +187 -0
  120. data/vendor/wreq/src/lib.rs +586 -0
  121. data/vendor/wreq/src/proxy/mac.rs +82 -0
  122. data/vendor/wreq/src/proxy/matcher.rs +806 -0
  123. data/vendor/wreq/src/proxy/uds.rs +66 -0
  124. data/vendor/wreq/src/proxy/win.rs +31 -0
  125. data/vendor/wreq/src/proxy.rs +569 -0
  126. data/vendor/wreq/src/redirect.rs +575 -0
  127. data/vendor/wreq/src/retry.rs +198 -0
  128. data/vendor/wreq/src/sync.rs +129 -0
  129. data/vendor/wreq/src/tls/conn/cache.rs +123 -0
  130. data/vendor/wreq/src/tls/conn/cert_compression.rs +125 -0
  131. data/vendor/wreq/src/tls/conn/ext.rs +82 -0
  132. data/vendor/wreq/src/tls/conn/macros.rs +34 -0
  133. data/vendor/wreq/src/tls/conn/service.rs +138 -0
  134. data/vendor/wreq/src/tls/conn.rs +681 -0
  135. data/vendor/wreq/src/tls/keylog/handle.rs +64 -0
  136. data/vendor/wreq/src/tls/keylog.rs +99 -0
  137. data/vendor/wreq/src/tls/options.rs +464 -0
  138. data/vendor/wreq/src/tls/x509/identity.rs +122 -0
  139. data/vendor/wreq/src/tls/x509/parser.rs +71 -0
  140. data/vendor/wreq/src/tls/x509/store.rs +228 -0
  141. data/vendor/wreq/src/tls/x509.rs +68 -0
  142. data/vendor/wreq/src/tls.rs +154 -0
  143. data/vendor/wreq/src/trace.rs +55 -0
  144. data/vendor/wreq/src/util.rs +122 -0
  145. data/vendor/wreq/tests/badssl.rs +228 -0
  146. data/vendor/wreq/tests/brotli.rs +350 -0
  147. data/vendor/wreq/tests/client.rs +1098 -0
  148. data/vendor/wreq/tests/connector_layers.rs +227 -0
  149. data/vendor/wreq/tests/cookie.rs +306 -0
  150. data/vendor/wreq/tests/deflate.rs +347 -0
  151. data/vendor/wreq/tests/emulation.rs +260 -0
  152. data/vendor/wreq/tests/gzip.rs +347 -0
  153. data/vendor/wreq/tests/layers.rs +261 -0
  154. data/vendor/wreq/tests/multipart.rs +165 -0
  155. data/vendor/wreq/tests/proxy.rs +438 -0
  156. data/vendor/wreq/tests/redirect.rs +629 -0
  157. data/vendor/wreq/tests/retry.rs +135 -0
  158. data/vendor/wreq/tests/support/delay_server.rs +117 -0
  159. data/vendor/wreq/tests/support/error.rs +16 -0
  160. data/vendor/wreq/tests/support/layer.rs +183 -0
  161. data/vendor/wreq/tests/support/mod.rs +9 -0
  162. data/vendor/wreq/tests/support/server.rs +232 -0
  163. data/vendor/wreq/tests/timeouts.rs +281 -0
  164. data/vendor/wreq/tests/unix_socket.rs +135 -0
  165. data/vendor/wreq/tests/upgrade.rs +98 -0
  166. data/vendor/wreq/tests/zstd.rs +559 -0
  167. metadata +225 -0
@@ -0,0 +1,77 @@
1
+ use std::time::Duration;
2
+
3
+ use wreq::{
4
+ Client,
5
+ tls::{CertStore, TlsInfo},
6
+ };
7
+
8
+ /// Certificate Store Example
9
+ ///
10
+ /// In most cases, you don't need to manually configure certificate stores. wreq automatically
11
+ /// uses appropriate default certificates:
12
+ /// - With `webpki-roots` feature enabled: Uses Mozilla's maintained root certificate collection
13
+ /// - Without this feature: Uses system default certificate store paths
14
+ ///
15
+ /// Manual certificate store configuration is only needed in the following special cases:
16
+ ///
17
+ /// ## Scenarios requiring custom certificate store:
18
+ ///
19
+ /// ### 1. Self-signed Certificates
20
+ /// - Connect to internal services using self-signed certificates
21
+ /// - Test servers in development environments
22
+ ///
23
+ /// ### 2. Enterprise Internal CA
24
+ /// - Add root certificates from enterprise internal certificate authorities
25
+ /// - Access HTTPS services on corporate intranets
26
+ ///
27
+ /// ### 3. Certificate Updates and Management
28
+ /// - Dynamically update certificates in the certificate store
29
+ /// - Remove revoked or expired certificates
30
+ ///
31
+ /// ### 4. Compliance Requirements
32
+ /// - Special compliance requirements for certain industries or regions
33
+ /// - Need to use specific certificate collections
34
+ ///
35
+ /// ### 5. Performance Optimization
36
+ /// - Reduce certificate store size to improve TLS handshake performance
37
+ /// - Include only necessary root certificates
38
+ #[tokio::main]
39
+ async fn main() -> wreq::Result<()> {
40
+ // Create a client with a custom certificate store using webpki-roots
41
+ let client = Client::builder()
42
+ .cert_store(CertStore::from_der_certs(
43
+ webpki_root_certs::TLS_SERVER_ROOT_CERTS,
44
+ )?)
45
+ .build()?;
46
+
47
+ // Use the API you're already familiar with
48
+ client.get("https://www.google.com").send().await?;
49
+
50
+ // Self-signed certificate Client
51
+ // Skip certificate verification for self-signed certificates
52
+ let client = Client::builder()
53
+ .tls_info(true)
54
+ .cert_verification(false)
55
+ .build()?;
56
+
57
+ // Use the API you're already familiar with
58
+ let resp = client.get("https://self-signed.badssl.com/").send().await?;
59
+ if let Some(tls_info) = resp.extensions().get::<TlsInfo>() {
60
+ if let Some(peer_cert_der) = tls_info.peer_certificate() {
61
+ // Create self-signed certificate Store
62
+ let self_signed_store = CertStore::from_der_certs(&[peer_cert_der])?;
63
+
64
+ // Create a client with self-signed certificate store
65
+ let client = Client::builder()
66
+ .cert_store(self_signed_store)
67
+ .connect_timeout(Duration::from_secs(10))
68
+ .build()?;
69
+
70
+ // Use the API you're already familiar with
71
+ let resp = client.get("https://self-signed.badssl.com/").send().await?;
72
+ println!("{}", resp.text().await?);
73
+ }
74
+ }
75
+
76
+ Ok(())
77
+ }
@@ -0,0 +1,258 @@
1
+ // This example demonstrates how to delegate the connect calls, which contain TLS handshakes,
2
+ // to a secondary tokio runtime of lower OS thread priority using a custom tower layer.
3
+ // This helps to ensure that long-running futures during handshake crypto operations don't block
4
+ // other I/O futures.
5
+ //
6
+ // This does introduce overhead of additional threads, channels, extra vtables, etc,
7
+ // so it is best suited to services with large numbers of incoming connections or that
8
+ // are otherwise very sensitive to any blocking futures. Or, you might want fewer threads
9
+ // and/or to use the current_thread runtime.
10
+ //
11
+ // This is using the `tokio` runtime and certain other dependencies:
12
+ //
13
+ // `tokio = { version = "1", features = ["full"] }`
14
+ // `libc = "0"`
15
+ // `pin-project-lite = "0.2"`
16
+ // `tower = { version = "0.5", default-features = false}`
17
+
18
+ #[tokio::main]
19
+ async fn main() -> wreq::Result<()> {
20
+ tracing_subscriber::fmt()
21
+ .with_max_level(tracing::Level::TRACE)
22
+ .init();
23
+ background_threadpool::init_background_runtime();
24
+ tokio::time::sleep(std::time::Duration::from_millis(10)).await;
25
+
26
+ let client = wreq::Client::builder()
27
+ .connector_layer(background_threadpool::BackgroundProcessorLayer::new())
28
+ .build()
29
+ .expect("should be able to build wreq client");
30
+
31
+ let url = if let Some(url) = std::env::args().nth(1) {
32
+ url
33
+ } else {
34
+ println!("No CLI URL provided, using default.");
35
+ "https://hyper.rs".into()
36
+ };
37
+
38
+ eprintln!("Fetching {url:?}...");
39
+
40
+ let res = client.get(url).send().await?;
41
+
42
+ eprintln!("Response: {:?} {}", res.version(), res.status());
43
+ eprintln!("Headers: {:#?}\n", res.headers());
44
+
45
+ let body = res.text().await?;
46
+
47
+ println!("{body}");
48
+
49
+ Ok(())
50
+ }
51
+
52
+ // separating out for convenience to avoid a million
53
+ mod background_threadpool {
54
+ use std::{
55
+ future::Future,
56
+ pin::Pin,
57
+ sync::OnceLock,
58
+ task::{Context, Poll},
59
+ };
60
+
61
+ use futures_util::TryFutureExt;
62
+ use pin_project_lite::pin_project;
63
+ use tokio::{runtime::Handle, select, sync::mpsc::error::TrySendError};
64
+ use tower::{BoxError, Layer, Service};
65
+
66
+ static CPU_HEAVY_THREAD_POOL: OnceLock<
67
+ tokio::sync::mpsc::Sender<Pin<Box<dyn Future<Output = ()> + Send + 'static>>>,
68
+ > = OnceLock::new();
69
+
70
+ pub(crate) fn init_background_runtime() {
71
+ std::thread::Builder::new()
72
+ .name("cpu-heavy-background-threadpool".to_string())
73
+ .spawn(move || {
74
+ let rt = tokio::runtime::Builder::new_multi_thread()
75
+ .thread_name("cpu-heavy-background-pool-thread")
76
+ .worker_threads(std::thread::available_parallelism().unwrap().get())
77
+ // ref: https://github.com/tokio-rs/tokio/issues/4941
78
+ // consider uncommenting if seeing heavy task contention
79
+ // .disable_lifo_slot()
80
+ .on_thread_start(move || {
81
+ #[cfg(target_os = "linux")]
82
+ unsafe {
83
+ // Increase thread pool thread niceness, so they are lower priority
84
+ // than the foreground executor and don't interfere with I/O tasks
85
+ {
86
+ *libc::__errno_location() = 0;
87
+ if libc::nice(10) == -1 && *libc::__errno_location() != 0 {
88
+ let error = std::io::Error::last_os_error();
89
+ tracing::error!("failed to set threadpool niceness: {error}");
90
+ }
91
+ }
92
+ }
93
+ })
94
+ .enable_all()
95
+ .build()
96
+ .unwrap_or_else(|e| panic!("cpu heavy runtime failed_to_initialize: {e}"));
97
+ rt.block_on(async {
98
+ tracing::debug!("starting background cpu-heavy work");
99
+ process_cpu_work().await;
100
+ });
101
+ })
102
+ .unwrap_or_else(|e| panic!("cpu heavy thread failed_to_initialize: {e}"));
103
+ }
104
+
105
+ async fn process_cpu_work() {
106
+ // we only use this channel for routing work, it should move pretty quick, it can be small
107
+ let (tx, mut rx) = tokio::sync::mpsc::channel(10);
108
+ // share the handle to the background channel globally
109
+ CPU_HEAVY_THREAD_POOL.set(tx).unwrap();
110
+
111
+ while let Some(work) = rx.recv().await {
112
+ tokio::task::spawn(work);
113
+ }
114
+ }
115
+
116
+ // retrieve the sender to the background channel, and send the future over to it for execution
117
+ fn send_to_background_runtime(future: impl Future<Output = ()> + Send + 'static) {
118
+ let tx = CPU_HEAVY_THREAD_POOL.get().expect(
119
+ "start up the secondary tokio runtime before sending to `CPU_HEAVY_THREAD_POOL`",
120
+ );
121
+
122
+ match tx.try_send(Box::pin(future)) {
123
+ Ok(_) => (),
124
+ Err(TrySendError::Closed(_)) => {
125
+ panic!("background cpu heavy runtime channel is closed")
126
+ }
127
+ Err(TrySendError::Full(msg)) => {
128
+ tracing::warn!(
129
+ "background cpu heavy runtime channel is full, task spawning loop delayed"
130
+ );
131
+ let tx = tx.clone();
132
+ Handle::current().spawn(async move {
133
+ tx.send(msg)
134
+ .await
135
+ .expect("background cpu heavy runtime channel is closed")
136
+ });
137
+ }
138
+ }
139
+ }
140
+
141
+ // This tower layer injects futures with a oneshot channel, and then sends them to the
142
+ // background runtime for processing. We don't use the Buffer service because that is
143
+ // intended to process sequentially on a single task, whereas we want to spawn a new task
144
+ // per call.
145
+ #[derive(Copy, Clone)]
146
+ pub struct BackgroundProcessorLayer {}
147
+ impl BackgroundProcessorLayer {
148
+ pub fn new() -> Self {
149
+ Self {}
150
+ }
151
+ }
152
+ impl<S> Layer<S> for BackgroundProcessorLayer {
153
+ type Service = BackgroundProcessor<S>;
154
+ fn layer(&self, service: S) -> Self::Service {
155
+ BackgroundProcessor::new(service)
156
+ }
157
+ }
158
+
159
+ impl std::fmt::Debug for BackgroundProcessorLayer {
160
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
161
+ f.debug_struct("BackgroundProcessorLayer").finish()
162
+ }
163
+ }
164
+
165
+ // This tower service injects futures with a oneshot channel, and then sends them to the
166
+ // background runtime for processing.
167
+ #[derive(Debug, Clone)]
168
+ pub struct BackgroundProcessor<S> {
169
+ inner: S,
170
+ }
171
+
172
+ impl<S> BackgroundProcessor<S> {
173
+ pub fn new(inner: S) -> Self {
174
+ BackgroundProcessor { inner }
175
+ }
176
+ }
177
+
178
+ impl<S, Request> Service<Request> for BackgroundProcessor<S>
179
+ where
180
+ S: Service<Request>,
181
+ S::Response: Send + 'static,
182
+ S::Error: Into<BoxError> + Send,
183
+ S::Future: Send + 'static,
184
+ {
185
+ type Response = S::Response;
186
+
187
+ type Error = BoxError;
188
+
189
+ type Future = BackgroundResponseFuture<S::Response>;
190
+
191
+ fn poll_ready(
192
+ &mut self,
193
+ cx: &mut std::task::Context<'_>,
194
+ ) -> std::task::Poll<Result<(), Self::Error>> {
195
+ match self.inner.poll_ready(cx) {
196
+ Poll::Pending => Poll::Pending,
197
+ Poll::Ready(r) => Poll::Ready(r.map_err(Into::into)),
198
+ }
199
+ }
200
+
201
+ fn call(&mut self, req: Request) -> Self::Future {
202
+ let response = self.inner.call(req);
203
+
204
+ // wrap our inner service's future with a future that writes to this oneshot channel
205
+ let (mut tx, rx) = tokio::sync::oneshot::channel();
206
+ let future = async move {
207
+ select!(
208
+ _ = tx.closed() => {
209
+ // receiver already dropped, don't need to do anything
210
+ }
211
+ result = response.map_err(Into::<BoxError>::into) => {
212
+ // if this fails, the receiver already dropped, so we don't need to do anything
213
+ let _ = tx.send(result);
214
+ }
215
+ )
216
+ };
217
+ // send the wrapped future to the background
218
+ send_to_background_runtime(future);
219
+
220
+ BackgroundResponseFuture::new(rx)
221
+ }
222
+ }
223
+
224
+ // `BackgroundProcessor` response future
225
+ pin_project! {
226
+ #[derive(Debug)]
227
+ pub struct BackgroundResponseFuture<S> {
228
+ #[pin]
229
+ rx: tokio::sync::oneshot::Receiver<Result<S, BoxError>>,
230
+ }
231
+ }
232
+
233
+ impl<S> BackgroundResponseFuture<S> {
234
+ pub(crate) fn new(rx: tokio::sync::oneshot::Receiver<Result<S, BoxError>>) -> Self {
235
+ BackgroundResponseFuture { rx }
236
+ }
237
+ }
238
+
239
+ impl<S> Future for BackgroundResponseFuture<S>
240
+ where
241
+ S: Send + 'static,
242
+ {
243
+ type Output = Result<S, BoxError>;
244
+
245
+ fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
246
+ let this = self.project();
247
+
248
+ // now poll on the receiver end of the oneshot to get the result
249
+ match this.rx.poll(cx) {
250
+ Poll::Ready(v) => match v {
251
+ Ok(v) => Poll::Ready(v),
252
+ Err(err) => Poll::Ready(Err(Box::new(err) as BoxError)),
253
+ },
254
+ Poll::Pending => Poll::Pending,
255
+ }
256
+ }
257
+ }
258
+ }
@@ -0,0 +1,118 @@
1
+ use wreq::{
2
+ Client, Emulation,
3
+ header::{self, HeaderMap, HeaderValue, OrigHeaderMap},
4
+ http2::{Http2Options, PseudoId, PseudoOrder},
5
+ tls::{AlpnProtocol, TlsOptions, TlsVersion},
6
+ };
7
+
8
+ macro_rules! join {
9
+ ($sep:expr, $first:expr $(, $rest:expr)*) => {
10
+ concat!($first $(, $sep, $rest)*)
11
+ };
12
+ }
13
+
14
+ #[tokio::main]
15
+ async fn main() -> wreq::Result<()> {
16
+ tracing_subscriber::fmt()
17
+ .with_max_level(tracing::Level::TRACE)
18
+ .init();
19
+
20
+ // TLS options config
21
+ let tls = TlsOptions::builder()
22
+ .enable_ocsp_stapling(true)
23
+ .curves_list(join!(":", "X25519", "P-256", "P-384"))
24
+ .cipher_list(join!(
25
+ ":",
26
+ "TLS_AES_128_GCM_SHA256",
27
+ "TLS_AES_256_GCM_SHA384",
28
+ "TLS_CHACHA20_POLY1305_SHA256",
29
+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
30
+ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
31
+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
32
+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
33
+ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
34
+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
35
+ ))
36
+ .sigalgs_list(join!(
37
+ ":",
38
+ "ecdsa_secp256r1_sha256",
39
+ "rsa_pss_rsae_sha256",
40
+ "rsa_pkcs1_sha256",
41
+ "ecdsa_secp384r1_sha384",
42
+ "rsa_pss_rsae_sha384",
43
+ "rsa_pkcs1_sha384",
44
+ "rsa_pss_rsae_sha512",
45
+ "rsa_pkcs1_sha512",
46
+ "rsa_pkcs1_sha1"
47
+ ))
48
+ .alpn_protocols([AlpnProtocol::HTTP2, AlpnProtocol::HTTP1])
49
+ .min_tls_version(TlsVersion::TLS_1_2)
50
+ .max_tls_version(TlsVersion::TLS_1_3)
51
+ .build();
52
+
53
+ // HTTP/2 options config
54
+ let http2 = Http2Options::builder()
55
+ .initial_stream_id(3)
56
+ .initial_window_size(16777216)
57
+ .initial_connection_window_size(16711681 + 65535)
58
+ .headers_pseudo_order(
59
+ PseudoOrder::builder()
60
+ .extend([
61
+ PseudoId::Method,
62
+ PseudoId::Path,
63
+ PseudoId::Authority,
64
+ PseudoId::Scheme,
65
+ ])
66
+ .build(),
67
+ )
68
+ .build();
69
+
70
+ // Default headers
71
+ let headers = {
72
+ let mut headers = HeaderMap::new();
73
+ headers.insert(header::USER_AGENT, HeaderValue::from_static("TwitterAndroid/10.89.0-release.0 (310890000-r-0) G011A/9 (google;G011A;google;G011A;0;;1;2016)"));
74
+ headers.insert(header::ACCEPT_LANGUAGE, HeaderValue::from_static("en-US"));
75
+ headers.insert(
76
+ header::ACCEPT_ENCODING,
77
+ HeaderValue::from_static("br, gzip, deflate"),
78
+ );
79
+ headers.insert(header::ACCEPT, HeaderValue::from_static("application/json"));
80
+ headers.insert(header::CACHE_CONTROL, HeaderValue::from_static("no-store"));
81
+ headers.insert(
82
+ header::COOKIE,
83
+ HeaderValue::from_static("ct0=YOUR_CT0_VALUE;"),
84
+ );
85
+ headers
86
+ };
87
+
88
+ // The headers keep the original case and order
89
+ let orig_headers = {
90
+ let mut orig_headers = OrigHeaderMap::new();
91
+ orig_headers.insert("cookie");
92
+ orig_headers.insert("content-length");
93
+ orig_headers.insert("User-Agent");
94
+ orig_headers.insert("Accept-Language");
95
+ orig_headers.insert("Accept-Encoding");
96
+ orig_headers
97
+ };
98
+
99
+ // This provider encapsulates TLS, HTTP/1, HTTP/2, default headers, and original headers
100
+ let emulation = Emulation::builder()
101
+ .tls_options(tls)
102
+ .http2_options(http2)
103
+ .headers(headers)
104
+ .orig_headers(orig_headers)
105
+ .build();
106
+
107
+ // Build a client with emulation config
108
+ let client = Client::builder()
109
+ .emulation(emulation)
110
+ .cert_verification(false)
111
+ .build()?;
112
+
113
+ // Use the API you're already familiar with
114
+ let resp = client.get("https://tls.browserleaks.com/").send().await?;
115
+ println!("{}", resp.text().await?);
116
+
117
+ Ok(())
118
+ }
@@ -0,0 +1,14 @@
1
+ // Short example of a POST request with form data.
2
+ //
3
+ // This is using the `tokio` runtime. You'll need the following dependency:
4
+ //
5
+ // `tokio = { version = "1", features = ["full"] }`
6
+ #[tokio::main]
7
+ async fn main() {
8
+ let response = wreq::post("http://www.baidu.com")
9
+ .form(&[("one", "1")])
10
+ .send()
11
+ .await
12
+ .expect("send");
13
+ println!("Response status {}", response.status());
14
+ }
@@ -0,0 +1,37 @@
1
+ use futures_util::{SinkExt, StreamExt, TryStreamExt};
2
+ use wreq::{header, ws::message::Message};
3
+
4
+ #[tokio::main]
5
+ async fn main() -> wreq::Result<()> {
6
+ // Use the API you're already familiar with
7
+ let resp = wreq::websocket("wss://echo.websocket.org")
8
+ .header(header::USER_AGENT, env!("CARGO_PKG_NAME"))
9
+ .read_buffer_size(1024 * 1024)
10
+ .send()
11
+ .await?;
12
+
13
+ assert_eq!(resp.version(), http::Version::HTTP_11);
14
+
15
+ let websocket = resp.into_websocket().await?;
16
+ if let Some(protocol) = websocket.protocol() {
17
+ println!("WebSocket subprotocol: {:?}", protocol);
18
+ }
19
+
20
+ let (mut tx, mut rx) = websocket.split();
21
+
22
+ tokio::spawn(async move {
23
+ for i in 1..11 {
24
+ if let Err(err) = tx.send(Message::text(format!("Hello, World! {i}"))).await {
25
+ eprintln!("failed to send message: {err}");
26
+ }
27
+ }
28
+ });
29
+
30
+ while let Some(message) = rx.try_next().await? {
31
+ if let Message::Text(text) = message {
32
+ println!("received: {text}");
33
+ }
34
+ }
35
+
36
+ Ok(())
37
+ }
@@ -0,0 +1,45 @@
1
+ //! Run websocket server
2
+ //!
3
+ //! ```not_rust
4
+ //! git clone https://github.com/tokio-rs/axum && cd axum
5
+ //! cargo run -p example-websockets-http2
6
+ //! ```
7
+
8
+ use futures_util::{SinkExt, StreamExt, TryStreamExt};
9
+ use wreq::{header, ws::message::Message};
10
+
11
+ #[tokio::main]
12
+ async fn main() -> wreq::Result<()> {
13
+ // Use the API you're already familiar with
14
+ let resp = wreq::websocket("wss://127.0.0.1:3000/ws")
15
+ .force_http2()
16
+ .header(header::USER_AGENT, env!("CARGO_PKG_NAME"))
17
+ .read_buffer_size(1024 * 1024)
18
+ .send()
19
+ .await?;
20
+
21
+ assert_eq!(resp.version(), http::Version::HTTP_2);
22
+
23
+ let websocket = resp.into_websocket().await?;
24
+ if let Some(protocol) = websocket.protocol() {
25
+ println!("WebSocket subprotocol: {:?}", protocol);
26
+ }
27
+
28
+ let (mut tx, mut rx) = websocket.split();
29
+
30
+ tokio::spawn(async move {
31
+ for i in 1..11 {
32
+ if let Err(err) = tx.send(Message::text(format!("Hello, World! #{i}"))).await {
33
+ eprintln!("failed to send message: {err}");
34
+ }
35
+ }
36
+ });
37
+
38
+ while let Some(message) = rx.try_next().await? {
39
+ if let Message::Text(text) = message {
40
+ println!("received: {text}");
41
+ }
42
+ }
43
+
44
+ Ok(())
45
+ }
@@ -0,0 +1,41 @@
1
+ //! This example illustrates the way to send and receive arbitrary JSON.
2
+ //!
3
+ //! This is useful for some ad-hoc experiments and situations when you don't
4
+ //! really care about the structure of the JSON and just need to display it or
5
+ //! process it at runtime.
6
+
7
+ // This is using the `tokio` runtime. You'll need the following dependency:
8
+ //
9
+ // `tokio = { version = "1", features = ["full"] }`
10
+ #[tokio::main]
11
+ async fn main() -> wreq::Result<()> {
12
+ let echo_json: serde_json::Value = wreq::post("https://jsonplaceholder.typicode.com/posts")
13
+ .json(&serde_json::json!({
14
+ "title": "wreq.rs",
15
+ "body": "https://docs.rs/wreq",
16
+ "userId": 1
17
+ }))
18
+ .send()
19
+ .await?
20
+ .json()
21
+ .await?;
22
+
23
+ println!("{echo_json:#?}");
24
+ // Object(
25
+ // {
26
+ // "body": String(
27
+ // "https://docs.rs/wreq"
28
+ // ),
29
+ // "id": Number(
30
+ // 101
31
+ // ),
32
+ // "title": String(
33
+ // "wreq.rs"
34
+ // ),
35
+ // "userId": Number(
36
+ // 1
37
+ // )
38
+ // }
39
+ // )
40
+ Ok(())
41
+ }
@@ -0,0 +1,47 @@
1
+ //! This example illustrates the way to send and receive statically typed JSON.
2
+ //!
3
+ //! In contrast to the arbitrary JSON example, this brings up the full power of
4
+ //! Rust compile-time type system guaranties though it requires a little bit
5
+ //! more code.
6
+
7
+ // These require the `serde` dependency.
8
+ use serde::{Deserialize, Serialize};
9
+
10
+ #[derive(Debug, Serialize, Deserialize)]
11
+ struct Post {
12
+ id: Option<i32>,
13
+ title: String,
14
+ body: String,
15
+ #[serde(rename = "userId")]
16
+ user_id: i32,
17
+ }
18
+
19
+ // This is using the `tokio` runtime. You'll need the following dependency:
20
+ //
21
+ // `tokio = { version = "1", features = ["full"] }`
22
+ #[tokio::main]
23
+ async fn main() -> wreq::Result<()> {
24
+ let new_post = Post {
25
+ id: None,
26
+ title: "wreq.rs".into(),
27
+ body: "https://docs.rs/wreq".into(),
28
+ user_id: 1,
29
+ };
30
+ let new_post: Post = wreq::post("https://jsonplaceholder.typicode.com/posts")
31
+ .json(&new_post)
32
+ .send()
33
+ .await?
34
+ .json()
35
+ .await?;
36
+
37
+ println!("{new_post:#?}");
38
+ // Post {
39
+ // id: Some(
40
+ // 101
41
+ // ),
42
+ // title: "wreq.rs",
43
+ // body: "https://docs.rs/wreq",
44
+ // user_id: 1
45
+ // }
46
+ Ok(())
47
+ }
@@ -0,0 +1,16 @@
1
+ use wreq::tls::KeyLog;
2
+
3
+ #[tokio::main]
4
+ async fn main() -> wreq::Result<()> {
5
+ // Build a client
6
+ let client = wreq::Client::builder()
7
+ .keylog(KeyLog::from_file("keylog.txt"))
8
+ .cert_verification(false)
9
+ .build()?;
10
+
11
+ // Use the API you're already familiar with
12
+ let resp = client.get("https://yande.re/post.json").send().await?;
13
+ println!("{}", resp.text().await?);
14
+
15
+ Ok(())
16
+ }