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,398 @@
1
+ //! Extension utilities.
2
+
3
+ use bytes::Bytes;
4
+ use http::uri::{Authority, Scheme, Uri};
5
+ use percent_encoding::{AsciiSet, CONTROLS};
6
+
7
+ use crate::Body;
8
+
9
+ /// See: <https://url.spec.whatwg.org/#fragment-percent-encode-set>
10
+ const FRAGMENT: &AsciiSet = &CONTROLS.add(b' ').add(b'"').add(b'<').add(b'>').add(b'`');
11
+
12
+ /// See: <https://url.spec.whatwg.org/#path-percent-encode-set>
13
+ const PATH: &AsciiSet = &FRAGMENT.add(b'#').add(b'?').add(b'{').add(b'}');
14
+
15
+ /// See: <https://url.spec.whatwg.org/#userinfo-percent-encode-set>
16
+ const USERINFO: &AsciiSet = &PATH
17
+ .add(b'/')
18
+ .add(b':')
19
+ .add(b';')
20
+ .add(b'=')
21
+ .add(b'@')
22
+ .add(b'[')
23
+ .add(b'\\')
24
+ .add(b']')
25
+ .add(b'^')
26
+ .add(b'|');
27
+
28
+ /// Extension trait for http::Response objects
29
+ ///
30
+ /// Provides methods to extract URI information from HTTP responses
31
+ pub trait ResponseExt {
32
+ /// Returns a reference to the `Uri` associated with this response, if available.
33
+ fn uri(&self) -> Option<&Uri>;
34
+ }
35
+
36
+ /// Extension trait for http::response::Builder objects
37
+ ///
38
+ /// Allows the user to add a `Uri` to the http::Response
39
+ pub trait ResponseBuilderExt {
40
+ /// A builder method for the `http::response::Builder` type that allows the user to add a `Uri`
41
+ /// to the `http::Response`
42
+ fn uri(self, uri: Uri) -> Self;
43
+ }
44
+
45
+ /// Extension type to store the request URI in a response's extensions.
46
+ #[derive(Clone)]
47
+ pub(crate) struct RequestUri(pub Uri);
48
+
49
+ /// Extension trait for `Uri` helpers.
50
+ pub(crate) trait UriExt {
51
+ /// Returns true if the URI scheme is HTTP.
52
+ fn is_http(&self) -> bool;
53
+
54
+ /// Returns true if the URI scheme is HTTPS.
55
+ fn is_https(&self) -> bool;
56
+
57
+ /// Returns the port of the URI, or the default port for the scheme if none is specified.
58
+ fn port_or_default(&self) -> u16;
59
+
60
+ /// Sets the query component of the URI, replacing any existing query.
61
+ #[cfg(feature = "query")]
62
+ fn set_query(&mut self, query: String);
63
+
64
+ /// Returns the username and password from the URI's userinfo, if present.
65
+ fn userinfo(&self) -> (Option<&str>, Option<&str>);
66
+
67
+ /// Sets the username and password in the URI's userinfo component.
68
+ fn set_userinfo(&mut self, username: &str, password: Option<&str>);
69
+ }
70
+
71
+ // ===== impl ResponseExt =====
72
+
73
+ impl ResponseExt for http::Response<Body> {
74
+ fn uri(&self) -> Option<&Uri> {
75
+ self.extensions().get::<RequestUri>().map(|r| &r.0)
76
+ }
77
+ }
78
+
79
+ // ===== impl ResponseBuilderExt =====
80
+
81
+ impl ResponseBuilderExt for http::response::Builder {
82
+ fn uri(self, uri: Uri) -> Self {
83
+ self.extension(RequestUri(uri))
84
+ }
85
+ }
86
+
87
+ // ===== impl UriExt =====
88
+
89
+ impl UriExt for Uri {
90
+ #[inline]
91
+ fn is_http(&self) -> bool {
92
+ self.scheme() == Some(&Scheme::HTTP)
93
+ }
94
+
95
+ #[inline]
96
+ fn is_https(&self) -> bool {
97
+ self.scheme() == Some(&Scheme::HTTPS)
98
+ }
99
+
100
+ fn port_or_default(&self) -> u16 {
101
+ match Uri::port(self) {
102
+ Some(p) => p.as_u16(),
103
+ None if self.is_https() => 443u16,
104
+ _ => 80u16,
105
+ }
106
+ }
107
+
108
+ #[cfg(feature = "query")]
109
+ fn set_query(&mut self, query: String) {
110
+ use http::uri::PathAndQuery;
111
+
112
+ if query.is_empty() {
113
+ return;
114
+ }
115
+
116
+ let path = self.path();
117
+ let parts = match PathAndQuery::from_maybe_shared(Bytes::from(format!("{path}?{query}"))) {
118
+ Ok(path_and_query) => {
119
+ let mut parts = self.clone().into_parts();
120
+ parts.path_and_query.replace(path_and_query);
121
+ parts
122
+ }
123
+ Err(_err) => {
124
+ debug!("Failed to set query in URI: {_err}");
125
+ return;
126
+ }
127
+ };
128
+
129
+ if let Ok(uri) = Uri::from_parts(parts) {
130
+ *self = uri;
131
+ }
132
+ }
133
+
134
+ fn userinfo(&self) -> (Option<&str>, Option<&str>) {
135
+ self.authority()
136
+ .and_then(|auth| auth.as_str().rsplit_once('@'))
137
+ .map_or((None, None), |(userinfo, _)| {
138
+ match userinfo.split_once(':') {
139
+ Some((u, p)) => ((!u.is_empty()).then_some(u), (!p.is_empty()).then_some(p)),
140
+ None => (Some(userinfo), None),
141
+ }
142
+ })
143
+ }
144
+
145
+ fn set_userinfo(&mut self, username: &str, password: Option<&str>) {
146
+ let mut parts = self.clone().into_parts();
147
+
148
+ let authority = match self.authority() {
149
+ Some(authority) => authority,
150
+ None => return,
151
+ };
152
+
153
+ let host_and_port = authority
154
+ .as_str()
155
+ .rsplit_once('@')
156
+ .map(|(_, host)| host)
157
+ .unwrap_or_else(|| authority.as_str());
158
+
159
+ let authority = match (username.is_empty(), password) {
160
+ (true, None) => Bytes::from(host_and_port.to_owned()),
161
+ (true, Some(password)) => {
162
+ let pass = percent_encoding::utf8_percent_encode(password, USERINFO);
163
+ Bytes::from(format!(":{pass}@{host_and_port}"))
164
+ }
165
+ (false, Some(password)) => {
166
+ let username = percent_encoding::utf8_percent_encode(username, USERINFO);
167
+ let password = percent_encoding::utf8_percent_encode(password, USERINFO);
168
+ Bytes::from(format!("{username}:{password}@{host_and_port}"))
169
+ }
170
+ (false, None) => {
171
+ let username = percent_encoding::utf8_percent_encode(username, USERINFO);
172
+ Bytes::from(format!("{username}@{host_and_port}"))
173
+ }
174
+ };
175
+
176
+ match Authority::from_maybe_shared(authority) {
177
+ Ok(authority) => {
178
+ parts.authority.replace(authority);
179
+ }
180
+ Err(_err) => {
181
+ debug!("Failed to set userinfo in URI: {_err}");
182
+ return;
183
+ }
184
+ };
185
+
186
+ if let Ok(uri) = Uri::from_parts(parts) {
187
+ *self = uri;
188
+ }
189
+ }
190
+ }
191
+
192
+ #[cfg(test)]
193
+ mod tests {
194
+ use http::{Uri, response::Builder};
195
+
196
+ use super::{RequestUri, ResponseBuilderExt, ResponseExt, UriExt};
197
+ use crate::Body;
198
+
199
+ #[test]
200
+ fn test_uri_ext_is_https() {
201
+ let https_uri: Uri = "https://example.com".parse().unwrap();
202
+ let http_uri: Uri = "http://example.com".parse().unwrap();
203
+
204
+ assert!(https_uri.is_https());
205
+ assert!(!http_uri.is_https());
206
+ assert!(http_uri.is_http());
207
+ assert!(!https_uri.is_http());
208
+ }
209
+
210
+ #[test]
211
+ fn test_userinfo_with_username_and_password() {
212
+ let uri: Uri = "http://user:pass@example.com".parse().unwrap();
213
+ let (username, password) = uri.userinfo();
214
+
215
+ assert_eq!(username, Some("user"));
216
+ assert_eq!(password, Some("pass"));
217
+ }
218
+
219
+ #[test]
220
+ fn test_userinfo_with_empty_username() {
221
+ let uri: Uri = "http://:pass@example.com".parse().unwrap();
222
+ let (username, password) = uri.userinfo();
223
+
224
+ assert_eq!(username, None);
225
+ assert_eq!(password, Some("pass"));
226
+ }
227
+
228
+ #[test]
229
+ fn test_userinfo_with_empty_password() {
230
+ let uri: Uri = "http://user:@example.com".parse().unwrap();
231
+ let (username, password) = uri.userinfo();
232
+
233
+ assert_eq!(username, Some("user"));
234
+ assert_eq!(password, None);
235
+
236
+ let uri: Uri = "http://user@example.com".parse().unwrap();
237
+ let (username, password) = uri.userinfo();
238
+
239
+ assert_eq!(username, Some("user"));
240
+ assert_eq!(password, None);
241
+ }
242
+
243
+ #[test]
244
+ fn test_userinfo_without_colon() {
245
+ let uri: Uri = "http://something@example.com".parse().unwrap();
246
+ let (username, password) = uri.userinfo();
247
+
248
+ assert_eq!(username, Some("something"));
249
+ assert_eq!(password, None);
250
+ }
251
+
252
+ #[test]
253
+ fn test_userinfo_without_at() {
254
+ let uri: Uri = "http://example.com".parse().unwrap();
255
+ let (username, password) = uri.userinfo();
256
+
257
+ assert_eq!(username, None);
258
+ assert_eq!(password, None);
259
+ }
260
+
261
+ #[test]
262
+ fn test_set_userinfo_both() {
263
+ let mut uri: Uri = "http://example.com/path".parse().unwrap();
264
+ uri.set_userinfo("user", Some("pass"));
265
+
266
+ let (username, password) = uri.userinfo();
267
+ assert_eq!(username, Some("user"));
268
+ assert_eq!(password, Some("pass"));
269
+ assert_eq!(uri.to_string(), "http://user:pass@example.com/path");
270
+ }
271
+
272
+ #[test]
273
+ fn test_set_userinfo_empty_username() {
274
+ let mut uri: Uri = "http://user:pass@example.com/path".parse().unwrap();
275
+ uri.set_userinfo("", Some("pass"));
276
+
277
+ let (username, password) = uri.userinfo();
278
+ assert_eq!(username, None);
279
+ assert_eq!(password, Some("pass"));
280
+ assert_eq!(uri.to_string(), "http://:pass@example.com/path");
281
+ }
282
+
283
+ #[test]
284
+ fn test_set_userinfo_none_password() {
285
+ let mut uri: Uri = "http://user:pass@example.com/path".parse().unwrap();
286
+ uri.set_userinfo("user", None);
287
+
288
+ let (username, password) = uri.userinfo();
289
+ assert_eq!(username, Some("user"));
290
+ assert_eq!(password, None);
291
+ assert_eq!(uri.to_string(), "http://user@example.com/path");
292
+ }
293
+
294
+ #[test]
295
+ fn test_set_userinfo_empty_username_and_password() {
296
+ let mut uri: Uri = "http://user:pass@example.com/path".parse().unwrap();
297
+ uri.set_userinfo("", None);
298
+
299
+ let (username, password) = uri.userinfo();
300
+ assert_eq!(username, None);
301
+ assert_eq!(password, None);
302
+ assert_eq!(uri.to_string(), "http://example.com/path");
303
+ }
304
+
305
+ #[test]
306
+ fn test_set_userinfo_with_encoding() {
307
+ use http::Uri;
308
+
309
+ use crate::ext::UriExt;
310
+
311
+ let mut uri: Uri = "http://example.com/path".parse().unwrap();
312
+ uri.set_userinfo("us er", Some("p@ss:word!"));
313
+
314
+ let (username, password) = uri.userinfo();
315
+ assert_eq!(username, Some("us%20er"));
316
+ assert_eq!(password, Some("p%40ss%3Aword!"));
317
+
318
+ assert_eq!(
319
+ uri.to_string(),
320
+ "http://us%20er:p%40ss%3Aword!@example.com/path"
321
+ );
322
+ }
323
+
324
+ #[test]
325
+ fn test_set_userinfo_only_username_with_encoding() {
326
+ use http::Uri;
327
+
328
+ use crate::ext::UriExt;
329
+
330
+ let mut uri: Uri = "http://example.com/".parse().unwrap();
331
+ uri.set_userinfo("user name", None);
332
+
333
+ let (username, password) = uri.userinfo();
334
+ assert_eq!(username, Some("user%20name"));
335
+ assert_eq!(password, None);
336
+
337
+ assert_eq!(uri.to_string(), "http://user%20name@example.com/");
338
+ }
339
+
340
+ #[test]
341
+ fn test_set_userinfo_only_password_with_encoding() {
342
+ use http::Uri;
343
+
344
+ use crate::ext::UriExt;
345
+
346
+ let mut uri: Uri = "http://example.com/".parse().unwrap();
347
+ uri.set_userinfo("", Some("p@ss word"));
348
+
349
+ let (username, password) = uri.userinfo();
350
+ assert_eq!(username, None);
351
+ assert_eq!(password, Some("p%40ss%20word"));
352
+
353
+ assert_eq!(uri.to_string(), "http://:p%40ss%20word@example.com/");
354
+ }
355
+
356
+ #[cfg(feature = "query")]
357
+ #[test]
358
+ fn test_set_query() {
359
+ let mut uri: Uri = "http://example.com/path".parse().unwrap();
360
+ uri.set_query("key=value&foo=bar".to_string());
361
+
362
+ assert_eq!(uri.to_string(), "http://example.com/path?key=value&foo=bar");
363
+
364
+ let mut uri: Uri = "http://example.com/path?existing=param".parse().unwrap();
365
+ uri.set_query("newkey=newvalue".to_string());
366
+
367
+ assert_eq!(uri.to_string(), "http://example.com/path?newkey=newvalue");
368
+
369
+ let mut uri: Uri = "http://example.com/path".parse().unwrap();
370
+ uri.set_query("".to_string());
371
+
372
+ assert_eq!(uri.to_string(), "http://example.com/path");
373
+ }
374
+
375
+ #[test]
376
+ fn test_response_builder_ext() {
377
+ let uri = Uri::try_from("http://example.com").unwrap();
378
+ let response = Builder::new()
379
+ .status(200)
380
+ .uri(uri.clone())
381
+ .body(Body::empty())
382
+ .unwrap();
383
+
384
+ assert_eq!(response.uri(), Some(&uri));
385
+ }
386
+
387
+ #[test]
388
+ fn test_response_ext() {
389
+ let uri = Uri::try_from("http://example.com").unwrap();
390
+ let response = http::Response::builder()
391
+ .status(200)
392
+ .extension(RequestUri(uri.clone()))
393
+ .body(Body::empty())
394
+ .unwrap();
395
+
396
+ assert_eq!(response.uri(), Some(&uri));
397
+ }
398
+ }
@@ -0,0 +1,143 @@
1
+ use std::{
2
+ borrow::Borrow,
3
+ hash::{BuildHasher, Hash, Hasher},
4
+ num::NonZeroU64,
5
+ sync::atomic::{AtomicU64, Ordering},
6
+ };
7
+
8
+ use ahash::RandomState;
9
+ use schnellru::ByLength;
10
+
11
+ /// Pre-seeded [`RandomState`] for consistent internal hashing.
12
+ ///
13
+ /// Uses fixed seeds to ensure deterministic hashing behavior across
14
+ /// program runs. Primarily used for connection pools and internal caches.
15
+ ///
16
+ /// **Note**: Not cryptographically secure due to fixed seeds.
17
+ pub const HASHER: RandomState = RandomState::with_seeds(
18
+ 0x6b68_d618_a4b5_3c57,
19
+ 0xadc8_c4d5_82bb_1313,
20
+ 0x2f72_c2c1_9b04_2d4c,
21
+ 0x94e5_8d83_a26c_3f28,
22
+ );
23
+
24
+ /// A type alias for a hash set using `ahash` with a pre-seeded `RandomState`.
25
+ pub type HashSet<T> = std::collections::HashSet<T, RandomState>;
26
+
27
+ /// A type alias for a hash map using `ahash` with a pre-seeded `RandomState`.
28
+ pub type HashMap<K, V> = std::collections::HashMap<K, V, RandomState>;
29
+
30
+ /// A specialized LRU cache using `schnellru` with a fixed capacity
31
+ pub type LruMap<K, V> = schnellru::LruMap<K, V, ByLength, RandomState>;
32
+
33
+ /// A wrapper that memoizes the hash value of its contained data.
34
+ #[derive(Debug)]
35
+ pub struct HashMemo<T, H: BuildHasher = RandomState>
36
+ where
37
+ T: Eq + PartialEq + Hash,
38
+ {
39
+ value: T,
40
+ hash: AtomicU64,
41
+ hasher: H,
42
+ }
43
+
44
+ impl<T, H> HashMemo<T, H>
45
+ where
46
+ T: Eq + Hash,
47
+ H: BuildHasher,
48
+ {
49
+ /// Creates a new `HashMemo` with a custom hasher.
50
+ ///
51
+ /// This allows you to specify a custom `BuildHasher` implementation for
52
+ /// controlling how hash values are computed.
53
+ pub const fn with_hasher(value: T, hasher: H) -> Self {
54
+ Self {
55
+ value,
56
+ hash: AtomicU64::new(u64::MIN),
57
+ hasher,
58
+ }
59
+ }
60
+ }
61
+
62
+ impl<T, H> Hash for HashMemo<T, H>
63
+ where
64
+ T: Eq + Hash,
65
+ H: BuildHasher,
66
+ {
67
+ fn hash<H2: Hasher>(&self, state: &mut H2) {
68
+ let hash = self.hash.load(Ordering::Relaxed);
69
+ if hash != 0 {
70
+ state.write_u64(hash);
71
+ return;
72
+ }
73
+
74
+ let computed_hash = NonZeroU64::new(self.hasher.hash_one(&self.value))
75
+ .map(NonZeroU64::get)
76
+ .unwrap_or(1);
77
+
78
+ let _ = self.hash.compare_exchange(
79
+ u64::MIN,
80
+ computed_hash,
81
+ Ordering::Relaxed,
82
+ Ordering::Relaxed,
83
+ );
84
+ state.write_u64(computed_hash);
85
+ }
86
+ }
87
+
88
+ impl<T, H> PartialOrd for HashMemo<T, H>
89
+ where
90
+ T: Eq + Hash + PartialOrd,
91
+ H: BuildHasher,
92
+ {
93
+ fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
94
+ self.value.partial_cmp(&other.value)
95
+ }
96
+ }
97
+
98
+ impl<T, H> Ord for HashMemo<T, H>
99
+ where
100
+ T: Eq + Hash + Ord,
101
+ H: BuildHasher,
102
+ {
103
+ fn cmp(&self, other: &Self) -> std::cmp::Ordering {
104
+ self.value.cmp(&other.value)
105
+ }
106
+ }
107
+
108
+ impl<T, H> PartialEq for HashMemo<T, H>
109
+ where
110
+ T: Eq + Hash,
111
+ H: BuildHasher,
112
+ {
113
+ fn eq(&self, other: &Self) -> bool {
114
+ self.value == other.value
115
+ }
116
+ }
117
+
118
+ impl<T, H> Eq for HashMemo<T, H>
119
+ where
120
+ T: Eq + Hash,
121
+ H: BuildHasher,
122
+ {
123
+ }
124
+
125
+ impl<T, H> AsRef<T> for HashMemo<T, H>
126
+ where
127
+ T: Eq + Hash,
128
+ H: BuildHasher,
129
+ {
130
+ fn as_ref(&self) -> &T {
131
+ &self.value
132
+ }
133
+ }
134
+
135
+ impl<T, H> Borrow<T> for HashMemo<T, H>
136
+ where
137
+ T: Eq + Hash,
138
+ H: BuildHasher,
139
+ {
140
+ fn borrow(&self) -> &T {
141
+ &self.value
142
+ }
143
+ }