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,165 @@
1
+ mod support;
2
+ use http_body_util::BodyExt;
3
+ use pretty_env_logger::env_logger;
4
+ use support::server;
5
+
6
+ #[tokio::test]
7
+ async fn text_part() {
8
+ let _ = env_logger::try_init();
9
+
10
+ let form = wreq::multipart::Form::new().text("foo", "bar");
11
+
12
+ let expected_body = format!(
13
+ "\
14
+ --{0}\r\n\
15
+ Content-Disposition: form-data; name=\"foo\"\r\n\r\n\
16
+ bar\r\n\
17
+ --{0}--\r\n\
18
+ ",
19
+ form.boundary()
20
+ );
21
+
22
+ let ct = format!("multipart/form-data; boundary={}", form.boundary());
23
+
24
+ let server = server::http(move |mut req| {
25
+ let ct = ct.clone();
26
+ let expected_body = expected_body.clone();
27
+ async move {
28
+ assert_eq!(req.method(), "POST");
29
+ assert_eq!(req.headers()["content-type"], ct);
30
+ assert_eq!(
31
+ req.headers()["content-length"],
32
+ expected_body.len().to_string()
33
+ );
34
+
35
+ let mut full: Vec<u8> = Vec::new();
36
+ while let Some(item) = req.body_mut().frame().await {
37
+ full.extend(&*item.unwrap().into_data().unwrap());
38
+ }
39
+
40
+ assert_eq!(full, expected_body.as_bytes());
41
+
42
+ http::Response::default()
43
+ }
44
+ });
45
+
46
+ let url = format!("http://{}/multipart/1", server.addr());
47
+
48
+ let res = wreq::post(&url).multipart(form).send().await.unwrap();
49
+
50
+ assert_eq!(res.uri(), url.as_str());
51
+ assert_eq!(res.status(), wreq::StatusCode::OK);
52
+ }
53
+
54
+ #[cfg(feature = "stream")]
55
+ #[tokio::test]
56
+ async fn stream_part() {
57
+ use futures_util::{future, stream};
58
+
59
+ let _ = env_logger::try_init();
60
+
61
+ let stream = wreq::Body::wrap_stream(stream::once(future::ready(Ok::<_, wreq::Error>(
62
+ "part1 part2".to_owned(),
63
+ ))));
64
+ let part = wreq::multipart::Part::stream(stream);
65
+
66
+ let form = wreq::multipart::Form::new()
67
+ .text("foo", "bar")
68
+ .part("part_stream", part);
69
+
70
+ let expected_body = format!(
71
+ "\
72
+ --{0}\r\n\
73
+ Content-Disposition: form-data; name=\"foo\"\r\n\
74
+ \r\n\
75
+ bar\r\n\
76
+ --{0}\r\n\
77
+ Content-Disposition: form-data; name=\"part_stream\"\r\n\
78
+ \r\n\
79
+ part1 part2\r\n\
80
+ --{0}--\r\n\
81
+ ",
82
+ form.boundary()
83
+ );
84
+
85
+ let ct = format!("multipart/form-data; boundary={}", form.boundary());
86
+
87
+ let server = server::http(move |req| {
88
+ let ct = ct.clone();
89
+ let expected_body = expected_body.clone();
90
+ async move {
91
+ assert_eq!(req.method(), "POST");
92
+ assert_eq!(req.headers()["content-type"], ct);
93
+ assert_eq!(req.headers()["transfer-encoding"], "chunked");
94
+
95
+ let full = req.collect().await.unwrap().to_bytes();
96
+
97
+ assert_eq!(full, expected_body.as_bytes());
98
+
99
+ http::Response::default()
100
+ }
101
+ });
102
+
103
+ let url = format!("http://{}/multipart/1", server.addr());
104
+
105
+ let res = wreq::post(&url)
106
+ .multipart(form)
107
+ .send()
108
+ .await
109
+ .expect("Failed to post multipart");
110
+ assert_eq!(res.uri(), url.as_str());
111
+ assert_eq!(res.status(), wreq::StatusCode::OK);
112
+ }
113
+
114
+ #[cfg(feature = "stream")]
115
+ #[tokio::test]
116
+ async fn async_impl_file_part() {
117
+ let _ = env_logger::try_init();
118
+
119
+ let form = wreq::multipart::Form::new()
120
+ .file("foo", "Cargo.lock")
121
+ .await
122
+ .unwrap();
123
+
124
+ let fcontents = std::fs::read_to_string("Cargo.lock").unwrap();
125
+
126
+ let expected_body = format!(
127
+ "\
128
+ --{0}\r\n\
129
+ Content-Disposition: form-data; name=\"foo\"; filename=\"Cargo.lock\"\r\n\
130
+ Content-Type: application/octet-stream\r\n\r\n\
131
+ {1}\r\n\
132
+ --{0}--\r\n\
133
+ ",
134
+ form.boundary(),
135
+ fcontents
136
+ );
137
+
138
+ let ct = format!("multipart/form-data; boundary={}", form.boundary());
139
+
140
+ let server = server::http(move |req| {
141
+ let ct = ct.clone();
142
+ let expected_body = expected_body.clone();
143
+ async move {
144
+ assert_eq!(req.method(), "POST");
145
+ assert_eq!(req.headers()["content-type"], ct);
146
+ // files know their exact size
147
+ assert_eq!(
148
+ req.headers()["content-length"],
149
+ expected_body.len().to_string()
150
+ );
151
+ let full = req.collect().await.unwrap().to_bytes();
152
+
153
+ assert_eq!(full, expected_body.as_bytes());
154
+
155
+ http::Response::default()
156
+ }
157
+ });
158
+
159
+ let url = format!("http://{}/multipart/3", server.addr());
160
+
161
+ let res = wreq::post(&url).multipart(form).send().await.unwrap();
162
+
163
+ assert_eq!(res.uri(), url.as_str());
164
+ assert_eq!(res.status(), wreq::StatusCode::OK);
165
+ }
@@ -0,0 +1,438 @@
1
+ mod support;
2
+ use std::{env, sync::LazyLock};
3
+
4
+ use support::server;
5
+ use tokio::sync::Mutex;
6
+ use wreq::Client;
7
+
8
+ // serialize tests that read from / write to environment variables
9
+ static HTTP_PROXY_ENV_MUTEX: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
10
+
11
+ #[tokio::test]
12
+ async fn http_proxy() {
13
+ let url = "http://hyper.rs.local/prox";
14
+ let server = server::http(move |req| {
15
+ assert_eq!(req.method(), "GET");
16
+ assert_eq!(req.uri(), url);
17
+ assert_eq!(req.headers()["host"], "hyper.rs.local");
18
+
19
+ async { http::Response::default() }
20
+ });
21
+
22
+ let proxy = format!("http://{}", server.addr());
23
+
24
+ let res = Client::builder()
25
+ .proxy(wreq::Proxy::http(&proxy).unwrap())
26
+ .build()
27
+ .unwrap()
28
+ .get(url)
29
+ .send()
30
+ .await
31
+ .unwrap();
32
+
33
+ assert_eq!(res.uri(), url);
34
+ assert_eq!(res.status(), wreq::StatusCode::OK);
35
+ }
36
+
37
+ #[tokio::test]
38
+ async fn http_proxy_basic_auth() {
39
+ let url = "http://hyper.rs.local/prox";
40
+ let server = server::http(move |req| {
41
+ assert_eq!(req.method(), "GET");
42
+ assert_eq!(req.uri(), url);
43
+ assert_eq!(req.headers()["host"], "hyper.rs.local");
44
+ assert_eq!(
45
+ req.headers()["proxy-authorization"],
46
+ "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
47
+ );
48
+
49
+ async { http::Response::default() }
50
+ });
51
+
52
+ let proxy = format!("http://{}", server.addr());
53
+
54
+ let res = Client::builder()
55
+ .proxy(
56
+ wreq::Proxy::http(&proxy)
57
+ .unwrap()
58
+ .basic_auth("Aladdin", "open sesame"),
59
+ )
60
+ .build()
61
+ .unwrap()
62
+ .get(url)
63
+ .send()
64
+ .await
65
+ .unwrap();
66
+
67
+ assert_eq!(res.uri(), url);
68
+ assert_eq!(res.status(), wreq::StatusCode::OK);
69
+ }
70
+
71
+ #[tokio::test]
72
+ async fn http_proxy_basic_auth_parsed() {
73
+ let url = "http://hyper.rs.local/prox";
74
+ let server = server::http(move |req| {
75
+ assert_eq!(req.method(), "GET");
76
+ assert_eq!(req.uri(), url);
77
+ assert_eq!(req.headers()["host"], "hyper.rs.local");
78
+ assert_eq!(
79
+ req.headers()["proxy-authorization"],
80
+ "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
81
+ );
82
+
83
+ async { http::Response::default() }
84
+ });
85
+
86
+ let proxy = format!("http://Aladdin:open%20sesame@{}", server.addr());
87
+
88
+ let res = Client::builder()
89
+ .proxy(wreq::Proxy::http(&proxy).unwrap())
90
+ .build()
91
+ .unwrap()
92
+ .get(url)
93
+ .send()
94
+ .await
95
+ .unwrap();
96
+
97
+ assert_eq!(res.uri(), url);
98
+ assert_eq!(res.status(), wreq::StatusCode::OK);
99
+
100
+ let res = wreq::get(url)
101
+ .proxy(wreq::Proxy::http(&proxy).unwrap())
102
+ .send()
103
+ .await
104
+ .unwrap();
105
+
106
+ assert_eq!(res.uri(), url);
107
+ assert_eq!(res.status(), wreq::StatusCode::OK);
108
+ }
109
+
110
+ #[tokio::test]
111
+ async fn system_http_proxy_basic_auth_parsed() {
112
+ let url = "http://hyper.rs.local/prox";
113
+ let server = server::http(move |req| {
114
+ assert_eq!(req.method(), "GET");
115
+ assert_eq!(req.uri(), url);
116
+ assert_eq!(req.headers()["host"], "hyper.rs.local");
117
+ assert_eq!(
118
+ req.headers()["proxy-authorization"],
119
+ "Basic QWxhZGRpbjpvcGVuc2VzYW1l"
120
+ );
121
+
122
+ async { http::Response::default() }
123
+ });
124
+
125
+ // avoid races with other tests that change "http_proxy"
126
+ let _env_lock = HTTP_PROXY_ENV_MUTEX.lock().await;
127
+
128
+ // save system setting first.
129
+ let system_proxy = env::var("http_proxy");
130
+
131
+ // set-up http proxy.
132
+ unsafe {
133
+ env::set_var(
134
+ "http_proxy",
135
+ format!("http://Aladdin:opensesame@{}", server.addr()),
136
+ )
137
+ }
138
+
139
+ let res = Client::builder()
140
+ .build()
141
+ .unwrap()
142
+ .get(url)
143
+ .send()
144
+ .await
145
+ .unwrap();
146
+
147
+ assert_eq!(res.uri(), url);
148
+ assert_eq!(res.status(), wreq::StatusCode::OK);
149
+
150
+ // reset user setting.
151
+ unsafe {
152
+ match system_proxy {
153
+ Err(_) => env::remove_var("http_proxy"),
154
+ Ok(proxy) => env::set_var("http_proxy", proxy),
155
+ }
156
+ }
157
+ }
158
+
159
+ #[tokio::test]
160
+ async fn test_no_proxy() {
161
+ let server = server::http(move |req| {
162
+ assert_eq!(req.method(), "GET");
163
+ assert_eq!(req.uri(), "/4");
164
+
165
+ async { http::Response::default() }
166
+ });
167
+ let proxy = format!("http://{}", server.addr());
168
+ let url = format!("http://{}/4", server.addr());
169
+
170
+ // set up proxy and use no_proxy to clear up client builder proxies.
171
+ let res = Client::builder()
172
+ .proxy(wreq::Proxy::http(&proxy).unwrap())
173
+ .no_proxy()
174
+ .build()
175
+ .unwrap()
176
+ .get(&url)
177
+ .send()
178
+ .await
179
+ .unwrap();
180
+
181
+ assert_eq!(res.uri(), url.as_str());
182
+ assert_eq!(res.status(), wreq::StatusCode::OK);
183
+ }
184
+
185
+ #[tokio::test]
186
+ async fn test_using_system_proxy() {
187
+ let url = "http://not.a.real.sub.hyper.rs.local/prox";
188
+ let server = server::http(move |req| {
189
+ assert_eq!(req.method(), "GET");
190
+ assert_eq!(req.uri(), url);
191
+ assert_eq!(req.headers()["host"], "not.a.real.sub.hyper.rs.local");
192
+
193
+ async { http::Response::default() }
194
+ });
195
+
196
+ // avoid races with other tests that change "http_proxy"
197
+ let _env_lock = HTTP_PROXY_ENV_MUTEX.lock().await;
198
+
199
+ // save system setting first.
200
+ let system_proxy = env::var("http_proxy");
201
+ // set-up http proxy.
202
+ unsafe {
203
+ env::set_var("http_proxy", format!("http://{}", server.addr()));
204
+ }
205
+ // system proxy is used by default
206
+ let res = wreq::get(url).send().await.unwrap();
207
+
208
+ assert_eq!(res.uri(), url);
209
+ assert_eq!(res.status(), wreq::StatusCode::OK);
210
+
211
+ // reset user setting.
212
+ unsafe {
213
+ match system_proxy {
214
+ Err(_) => env::remove_var("http_proxy"),
215
+ Ok(proxy) => env::set_var("http_proxy", proxy),
216
+ }
217
+ }
218
+ }
219
+
220
+ #[tokio::test]
221
+ async fn http_over_http() {
222
+ let url = "http://hyper.rs.local/prox";
223
+
224
+ let server = server::http(move |req| {
225
+ assert_eq!(req.method(), "GET");
226
+ assert_eq!(req.uri(), url);
227
+ assert_eq!(req.headers()["host"], "hyper.rs.local");
228
+
229
+ async { http::Response::default() }
230
+ });
231
+
232
+ let proxy = format!("http://{}", server.addr());
233
+
234
+ let res = Client::builder()
235
+ .proxy(wreq::Proxy::http(&proxy).unwrap())
236
+ .build()
237
+ .unwrap()
238
+ .get(url)
239
+ .send()
240
+ .await
241
+ .unwrap();
242
+
243
+ assert_eq!(res.uri(), url);
244
+ assert_eq!(res.status(), wreq::StatusCode::OK);
245
+ }
246
+
247
+ #[tokio::test]
248
+ async fn http_proxy_custom_headers() {
249
+ let url = "http://hyper.rs.local/prox";
250
+ let server = server::http(move |req| {
251
+ assert_eq!(req.method(), "GET");
252
+ assert_eq!(req.uri(), url);
253
+ assert_eq!(req.headers()["host"], "hyper.rs.local");
254
+ assert_eq!(
255
+ req.headers()["proxy-authorization"],
256
+ "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
257
+ );
258
+ assert_eq!(req.headers()["x-custom-header"], "value");
259
+
260
+ async { http::Response::default() }
261
+ });
262
+
263
+ let proxy = format!("http://Aladdin:open%20sesame@{}", server.addr());
264
+
265
+ let proxy = wreq::Proxy::http(&proxy).unwrap().custom_http_headers({
266
+ let mut headers = http::HeaderMap::new();
267
+ headers.insert("x-custom-header", "value".parse().unwrap());
268
+ headers
269
+ });
270
+
271
+ let res = Client::builder()
272
+ .proxy(proxy.clone())
273
+ .build()
274
+ .unwrap()
275
+ .get(url)
276
+ .send()
277
+ .await
278
+ .unwrap();
279
+
280
+ assert_eq!(res.uri(), url);
281
+ assert_eq!(res.status(), wreq::StatusCode::OK);
282
+
283
+ let res = wreq::get(url).proxy(proxy).send().await.unwrap();
284
+
285
+ assert_eq!(res.uri(), url);
286
+ assert_eq!(res.status(), wreq::StatusCode::OK);
287
+ }
288
+
289
+ #[tokio::test]
290
+ async fn tunnel_detects_auth_required() {
291
+ let url = "https://hyper.rs.local/prox";
292
+
293
+ let server = server::http(move |req| {
294
+ assert_eq!(req.method(), "CONNECT");
295
+ assert_eq!(req.uri(), "hyper.rs.local:443");
296
+ assert!(
297
+ !req.headers()
298
+ .contains_key(http::header::PROXY_AUTHORIZATION)
299
+ );
300
+
301
+ async {
302
+ let mut res = http::Response::default();
303
+ *res.status_mut() = http::StatusCode::PROXY_AUTHENTICATION_REQUIRED;
304
+ res
305
+ }
306
+ });
307
+
308
+ let proxy = format!("http://{}", server.addr());
309
+
310
+ let err = Client::builder()
311
+ .proxy(wreq::Proxy::https(&proxy).unwrap())
312
+ .build()
313
+ .unwrap()
314
+ .get(url)
315
+ .send()
316
+ .await
317
+ .unwrap_err();
318
+
319
+ let err = support::error::inspect(err).pop().unwrap();
320
+ assert!(
321
+ err.contains("auth"),
322
+ "proxy auth err expected, got: {err:?}"
323
+ );
324
+ }
325
+
326
+ #[tokio::test]
327
+ async fn tunnel_includes_proxy_auth() {
328
+ let url = "https://hyper.rs.local/prox";
329
+
330
+ let server = server::http(move |req| {
331
+ assert_eq!(req.method(), "CONNECT");
332
+ assert_eq!(req.uri(), "hyper.rs.local:443");
333
+ assert_eq!(
334
+ req.headers()["proxy-authorization"],
335
+ "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
336
+ );
337
+
338
+ async {
339
+ // return 400 to not actually deal with TLS tunneling
340
+ let mut res = http::Response::default();
341
+ *res.status_mut() = http::StatusCode::BAD_REQUEST;
342
+ res
343
+ }
344
+ });
345
+
346
+ let proxy = format!("http://Aladdin:open%20sesame@{}", server.addr());
347
+
348
+ let err = Client::builder()
349
+ .proxy(wreq::Proxy::https(&proxy).unwrap())
350
+ .build()
351
+ .unwrap()
352
+ .get(url)
353
+ .send()
354
+ .await
355
+ .unwrap_err();
356
+
357
+ let err = support::error::inspect(err).pop().unwrap();
358
+ assert!(
359
+ err.contains("unsuccessful"),
360
+ "tunnel unsuccessful expected, got: {err:?}"
361
+ );
362
+ }
363
+
364
+ #[tokio::test]
365
+ async fn tunnel_includes_user_agent() {
366
+ let url = "https://hyper.rs.local/prox";
367
+
368
+ let server = server::http(move |req| {
369
+ assert_eq!(req.method(), "CONNECT");
370
+ assert_eq!(req.uri(), "hyper.rs.local:443");
371
+ assert_eq!(req.headers()["user-agent"], "wreq-test");
372
+
373
+ async {
374
+ // return 400 to not actually deal with TLS tunneling
375
+ let mut res = http::Response::default();
376
+ *res.status_mut() = http::StatusCode::BAD_REQUEST;
377
+ res
378
+ }
379
+ });
380
+
381
+ let proxy = format!("http://{}", server.addr());
382
+
383
+ let err = Client::builder()
384
+ .proxy(wreq::Proxy::https(&proxy).unwrap().custom_http_headers({
385
+ let mut headers = http::HeaderMap::new();
386
+ headers.insert("user-agent", "wreq-test".parse().unwrap());
387
+ headers
388
+ }))
389
+ .user_agent("wreq-test")
390
+ .build()
391
+ .unwrap()
392
+ .get(url)
393
+ .send()
394
+ .await
395
+ .unwrap_err();
396
+
397
+ let err = support::error::inspect(err).pop().unwrap();
398
+ assert!(
399
+ err.contains("unsuccessful"),
400
+ "tunnel unsuccessful expected, got: {err:?}"
401
+ );
402
+ }
403
+
404
+ #[tokio::test]
405
+ async fn proxy_tunnel_connect_error() {
406
+ let client = Client::builder()
407
+ .cert_verification(false)
408
+ .no_proxy()
409
+ .build()
410
+ .unwrap();
411
+
412
+ let invalid_proxies = vec![
413
+ "http://invalid.proxy:8080",
414
+ "https://invalid.proxy:8080",
415
+ "socks4://invalid.proxy:8080",
416
+ "socks4a://invalid.proxy:8080",
417
+ "socks5://invalid.proxy:8080",
418
+ "socks5h://invalid.proxy:8080",
419
+ ];
420
+
421
+ let target_urls = ["https://example.com", "http://example.com"];
422
+
423
+ for proxy in invalid_proxies {
424
+ for url in target_urls {
425
+ let err = client
426
+ .get(url)
427
+ .proxy(wreq::Proxy::all(proxy).unwrap())
428
+ .send()
429
+ .await
430
+ .unwrap_err();
431
+
432
+ assert!(
433
+ err.is_proxy_connect(),
434
+ "proxy connect error expected, got: {err:?}"
435
+ );
436
+ }
437
+ }
438
+ }