1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
use httpmock::MockServer;
use reqwest::blocking::Client;
#[test]
fn proxy_test() {
tracing_subscriber::fmt::init();
// We will create this mock server to simulate a real service (e.g., GitHub, AWS, etc.).
let target_server = MockServer::start();
target_server.mock(|when, then| {
when.any_request();
then.status(200).body("Hi from fake GitHub!");
});
// Let's create our mock server for the test
let proxy_server = MockServer::start();
// We configure our server to proxy the request to the target host instead of
// answering with a mocked response. The 'when' variable lets you configure
// rules under which requests are allowed to be proxied. If you do not restrict,
// any request will be proxied.
proxy_server.proxy(|rule| {
rule.filter(|when| {
// Here we only allow to proxy requests to our target server.
when.host(target_server.host()).port(target_server.port());
});
});
// The following will send a request to the mock server. The request will be forwarded
// to the target host, as we configured before.
let client = Client::builder()
.proxy(reqwest::Proxy::all(proxy_server.base_url()).unwrap()) // <<- Here we configure to use a proxy server
.build()
.unwrap();
// Since the request was forwarded, we should see the target host's response.
let response = client.get(target_server.url("/get")).send().unwrap();
// Extract the status code before calling .text() which consumes the response
let status_code = response.status().as_u16();
let response_text = response.text().unwrap(); // Store the text response in a variable
assert_eq!("Hi from fake GitHub!", response_text); // Use the stored text for comparison
assert_eq!(status_code, 200); // Now compare the status code
}
// When httpmock operates as an HTTPS MITM proxy, the client→proxy leg speaks origin-form ("/", with a Host header).
// Internally we normalize to absolute-form for matching/recording, but before sending upstream we convert back to
// origin-form. Many HTTPS origin servers (especially those negotiating HTTP/2, like google.com) reject absolute-form
// requests on origin connections, which previously caused a 500 with "client error (SendRequest)". With the
// conversion in place, both yahoo.com and google.com should return a normal redirect (301) here instead of failing.
#[cfg(feature = "https")]
#[test]
fn absolute_origin_form_test() {
let server = httpmock::MockServer::start();
server.proxy(|rule| {
rule.filter(|when| {
when.any_request();
});
});
let client = reqwest::blocking::ClientBuilder::new()
.proxy(reqwest::Proxy::all(server.base_url()).unwrap())
.redirect(reqwest::redirect::Policy::none())
.build()
.unwrap();
let response = client.get("https://yahoo.com/").send().unwrap();
assert_eq!(response.status(), 301);
let response = client.get("https://google.com/").send().unwrap();
assert_eq!(response.status(), 301);
}