pub struct Request { /* private fields */ }Expand description
A typed HTTP request for GET or HEAD.
Implementations§
Source§impl Request
impl Request
Sourcepub fn new<U: ToUrl>(method: Method, url: U) -> Result<Self, NanoGetError>
pub fn new<U: ToUrl>(method: Method, url: U) -> Result<Self, NanoGetError>
Creates a new request with the given method and URL.
Sourcepub fn get<U: ToUrl>(url: U) -> Result<Self, NanoGetError>
pub fn get<U: ToUrl>(url: U) -> Result<Self, NanoGetError>
Creates a new GET request.
Examples found in repository?
41fn main() -> Result<(), Box<dyn Error>> {
42 let Some(url) = env::var("NANO_GET_CUSTOM_AUTH_URL").ok() else {
43 print_setup();
44 return Ok(());
45 };
46
47 let client = Client::builder()
48 .auth_handler(Arc::new(DemoTokenAuth))
49 .build();
50 let response = client.execute(Request::get(&url)?)?;
51
52 println!("custom-auth-handler example");
53 println!(
54 "status: {} {}",
55 response.status_code, response.reason_phrase
56 );
57 println!(
58 "parsed WWW-Authenticate challenges: {}",
59 response.www_authenticate_challenges()?.len()
60 );
61
62 Ok(())
63}More examples
42fn bench_get(iterations: usize) -> Duration {
43 let response = b"HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nhello".to_vec();
44 let (base_url, handle) = spawn_persistent_server(iterations, response);
45
46 let client = Client::builder()
47 .connection_policy(ConnectionPolicy::Reuse)
48 .build();
49 let mut session = client.session();
50
51 let start = Instant::now();
52 for i in 0..iterations {
53 let req = Request::get(format!("{}/g{}", base_url, i)).expect("request");
54 let resp = session.execute(req).expect("execute");
55 assert_eq!(resp.body, b"hello");
56 }
57 let elapsed = start.elapsed();
58 handle.join().expect("join server");
59 elapsed
60}
61
62fn bench_head(iterations: usize) -> Duration {
63 let response = b"HTTP/1.1 200 OK\r\nContent-Length: 5\r\nX-Bench: 1\r\n\r\n".to_vec();
64 let (base_url, handle) = spawn_persistent_server(iterations, response);
65
66 let client = Client::builder()
67 .connection_policy(ConnectionPolicy::Reuse)
68 .build();
69 let mut session = client.session();
70
71 let start = Instant::now();
72 for i in 0..iterations {
73 let req = Request::head(format!("{}/h{}", base_url, i)).expect("request");
74 let resp = session.execute(req).expect("execute");
75 assert!(resp.body.is_empty());
76 }
77 let elapsed = start.elapsed();
78 handle.join().expect("join server");
79 elapsed
80}
81
82fn bench_pipeline(total_requests: usize, pipeline_depth: usize) -> Duration {
83 let response = b"HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nhello".to_vec();
84 let (base_url, handle) = spawn_persistent_server(total_requests, response);
85
86 let client = Client::builder()
87 .connection_policy(ConnectionPolicy::Reuse)
88 .build();
89 let mut session = client.session();
90
91 let start = Instant::now();
92 let mut sent = 0usize;
93 while sent < total_requests {
94 let batch_size = (total_requests - sent).min(pipeline_depth);
95 let mut batch = Vec::with_capacity(batch_size);
96 for index in 0..batch_size {
97 batch.push(Request::get(format!("{}/p{}", base_url, sent + index)).expect("request"));
98 }
99 let responses = session.execute_pipelined(&batch).expect("execute");
100 assert_eq!(responses.len(), batch_size);
101 for response in responses {
102 assert_eq!(response.body, b"hello");
103 }
104 sent += batch_size;
105 }
106 let elapsed = start.elapsed();
107 handle.join().expect("join server");
108 elapsed
109}14fn main() -> Result<(), Box<dyn Error>> {
15 let client = Client::builder()
16 .connection_policy(ConnectionPolicy::Reuse)
17 .build();
18 let mut session = client.session();
19
20 let first = session.execute(Request::get("http://example.com/")?)?;
21 let second = session.execute(Request::get("http://example.com/index.html")?)?;
22 let pipelined = session.execute_pipelined(&[
23 Request::get("http://example.com/")?,
24 Request::get("http://example.com/index.html")?,
25 ])?;
26
27 println!("This example demonstrates the Session API shape for reuse and pipelining.");
28 summarize("sequential #1", &first);
29 summarize("sequential #2", &second);
30 summarize("pipeline #1", &pipelined[0]);
31 summarize("pipeline #2", &pipelined[1]);
32
33 Ok(())
34}5fn main() -> Result<(), Box<dyn Error>> {
6 let client = Client::builder().cache_mode(CacheMode::Memory).build();
7
8 let first = Request::get("http://example.com")?;
9 let mut second = Request::get("http://example.com")?;
10 second.add_header("Cache-Control", "max-age=0, min-fresh=1")?;
11
12 let first_response = client.execute(first)?;
13 let second_response = client.execute(second)?;
14
15 println!("memory cache example");
16 println!(
17 "first response: {} {}",
18 first_response.status_code, first_response.reason_phrase
19 );
20 println!(
21 "second response with request directives: {} {}",
22 second_response.status_code, second_response.reason_phrase
23 );
24 println!("This example demonstrates cache configuration and cache-control request headers.");
25
26 Ok(())
27}14fn main() -> Result<(), Box<dyn Error>> {
15 let url = "http://example.com";
16 let mut request = Request::get(url)?.with_redirect_policy(RedirectPolicy::follow(5));
17
18 request.add_header("Accept", "text/html,application/xhtml+xml")?;
19 request.add_header("Cache-Control", "max-age=0")?;
20 request.if_none_match("\"demo-etag\"")?;
21 request.if_modified_since(UNIX_EPOCH + Duration::from_secs(784_111_777))?;
22 request.range_bytes(Some(0), Some(255))?;
23
24 // Protocol-managed headers such as Host and Connection are intentionally rejected by the
25 // library. This example only uses safe end-to-end request headers.
26 let response = request.execute()?;
27
28 println!("manual request to {url}");
29 println!(
30 "status: {} {}",
31 response.status_code, response.reason_phrase
32 );
33 println!("content-type: {:?}", response.header("content-type"));
34 println!("body preview: {}", preview_text(response.body_text()?, 80));
35
36 Ok(())
37}18fn main() -> Result<(), Box<dyn Error>> {
19 let Some(url) = env::var("NANO_GET_BASIC_AUTH_URL").ok() else {
20 print_setup();
21 return Ok(());
22 };
23
24 let user = env_or_default("NANO_GET_BASIC_AUTH_USER", "demo-user");
25 let pass = env_or_default("NANO_GET_BASIC_AUTH_PASS", "demo-pass");
26
27 let challenge_driven = Client::builder()
28 .basic_auth(user.clone(), pass.clone())
29 .build()
30 .execute(Request::get(&url)?)?;
31
32 let preemptive = Client::builder()
33 .preemptive_basic_auth(user.clone(), pass.clone())
34 .build()
35 .execute(Request::get(&url)?)?;
36
37 let mut request = Request::get(&url)?;
38 request.basic_auth(user, pass)?;
39 let manual = request.execute()?;
40
41 println!("basic-auth example");
42 println!("challenge-driven status: {}", challenge_driven.status_code);
43 println!("preemptive status: {}", preemptive.status_code);
44 println!("request-level override status: {}", manual.status_code);
45
46 Ok(())
47}Sourcepub fn head<U: ToUrl>(url: U) -> Result<Self, NanoGetError>
pub fn head<U: ToUrl>(url: U) -> Result<Self, NanoGetError>
Creates a new HEAD request.
Examples found in repository?
62fn bench_head(iterations: usize) -> Duration {
63 let response = b"HTTP/1.1 200 OK\r\nContent-Length: 5\r\nX-Bench: 1\r\n\r\n".to_vec();
64 let (base_url, handle) = spawn_persistent_server(iterations, response);
65
66 let client = Client::builder()
67 .connection_policy(ConnectionPolicy::Reuse)
68 .build();
69 let mut session = client.session();
70
71 let start = Instant::now();
72 for i in 0..iterations {
73 let req = Request::head(format!("{}/h{}", base_url, i)).expect("request");
74 let resp = session.execute(req).expect("execute");
75 assert!(resp.body.is_empty());
76 }
77 let elapsed = start.elapsed();
78 handle.join().expect("join server");
79 elapsed
80}Sourcepub fn header(&self, name: &str) -> Option<&str>
pub fn header(&self, name: &str) -> Option<&str>
Returns the first header value matching name (case-insensitive).
Sourcepub fn headers_named<'a>(
&'a self,
name: &'a str,
) -> impl Iterator<Item = &'a Header> + 'a
pub fn headers_named<'a>( &'a self, name: &'a str, ) -> impl Iterator<Item = &'a Header> + 'a
Iterates over all headers matching name (case-insensitive), preserving insertion order.
Sourcepub fn redirect_policy(&self) -> RedirectPolicy
pub fn redirect_policy(&self) -> RedirectPolicy
Returns this request’s redirect policy.
Sourcepub fn with_redirect_policy(self, policy: RedirectPolicy) -> Self
pub fn with_redirect_policy(self, policy: RedirectPolicy) -> Self
Sets redirect policy on this request using builder style.
Examples found in repository?
14fn main() -> Result<(), Box<dyn Error>> {
15 let url = "http://example.com";
16 let mut request = Request::get(url)?.with_redirect_policy(RedirectPolicy::follow(5));
17
18 request.add_header("Accept", "text/html,application/xhtml+xml")?;
19 request.add_header("Cache-Control", "max-age=0")?;
20 request.if_none_match("\"demo-etag\"")?;
21 request.if_modified_since(UNIX_EPOCH + Duration::from_secs(784_111_777))?;
22 request.range_bytes(Some(0), Some(255))?;
23
24 // Protocol-managed headers such as Host and Connection are intentionally rejected by the
25 // library. This example only uses safe end-to-end request headers.
26 let response = request.execute()?;
27
28 println!("manual request to {url}");
29 println!(
30 "status: {} {}",
31 response.status_code, response.reason_phrase
32 );
33 println!("content-type: {:?}", response.header("content-type"));
34 println!("body preview: {}", preview_text(response.body_text()?, 80));
35
36 Ok(())
37}Sourcepub fn set_redirect_policy(&mut self, policy: RedirectPolicy) -> &mut Self
pub fn set_redirect_policy(&mut self, policy: RedirectPolicy) -> &mut Self
Sets redirect policy on this request in-place.
Sourcepub fn add_header(
&mut self,
name: impl Into<String>,
value: impl Into<String>,
) -> Result<&mut Self, NanoGetError>
pub fn add_header( &mut self, name: impl Into<String>, value: impl Into<String>, ) -> Result<&mut Self, NanoGetError>
Appends a header without replacing existing headers of the same name.
Protocol-managed and hop-by-hop header names are rejected.
Examples found in repository?
5fn main() -> Result<(), Box<dyn Error>> {
6 let client = Client::builder().cache_mode(CacheMode::Memory).build();
7
8 let first = Request::get("http://example.com")?;
9 let mut second = Request::get("http://example.com")?;
10 second.add_header("Cache-Control", "max-age=0, min-fresh=1")?;
11
12 let first_response = client.execute(first)?;
13 let second_response = client.execute(second)?;
14
15 println!("memory cache example");
16 println!(
17 "first response: {} {}",
18 first_response.status_code, first_response.reason_phrase
19 );
20 println!(
21 "second response with request directives: {} {}",
22 second_response.status_code, second_response.reason_phrase
23 );
24 println!("This example demonstrates cache configuration and cache-control request headers.");
25
26 Ok(())
27}More examples
14fn main() -> Result<(), Box<dyn Error>> {
15 let url = "http://example.com";
16 let mut request = Request::get(url)?.with_redirect_policy(RedirectPolicy::follow(5));
17
18 request.add_header("Accept", "text/html,application/xhtml+xml")?;
19 request.add_header("Cache-Control", "max-age=0")?;
20 request.if_none_match("\"demo-etag\"")?;
21 request.if_modified_since(UNIX_EPOCH + Duration::from_secs(784_111_777))?;
22 request.range_bytes(Some(0), Some(255))?;
23
24 // Protocol-managed headers such as Host and Connection are intentionally rejected by the
25 // library. This example only uses safe end-to-end request headers.
26 let response = request.execute()?;
27
28 println!("manual request to {url}");
29 println!(
30 "status: {} {}",
31 response.status_code, response.reason_phrase
32 );
33 println!("content-type: {:?}", response.header("content-type"));
34 println!("body preview: {}", preview_text(response.body_text()?, 80));
35
36 Ok(())
37}Sourcepub fn set_header(
&mut self,
name: impl Into<String>,
value: impl Into<String>,
) -> Result<&mut Self, NanoGetError>
pub fn set_header( &mut self, name: impl Into<String>, value: impl Into<String>, ) -> Result<&mut Self, NanoGetError>
Sets a header value by removing existing headers with the same name first.
Protocol-managed and hop-by-hop header names are rejected.
Sourcepub fn remove_headers_named(&mut self, name: &str) -> &mut Self
pub fn remove_headers_named(&mut self, name: &str) -> &mut Self
Removes all headers with the provided name.
Sourcepub fn if_none_match(
&mut self,
etag: impl Into<String>,
) -> Result<&mut Self, NanoGetError>
pub fn if_none_match( &mut self, etag: impl Into<String>, ) -> Result<&mut Self, NanoGetError>
Sets If-None-Match.
Examples found in repository?
14fn main() -> Result<(), Box<dyn Error>> {
15 let url = "http://example.com";
16 let mut request = Request::get(url)?.with_redirect_policy(RedirectPolicy::follow(5));
17
18 request.add_header("Accept", "text/html,application/xhtml+xml")?;
19 request.add_header("Cache-Control", "max-age=0")?;
20 request.if_none_match("\"demo-etag\"")?;
21 request.if_modified_since(UNIX_EPOCH + Duration::from_secs(784_111_777))?;
22 request.range_bytes(Some(0), Some(255))?;
23
24 // Protocol-managed headers such as Host and Connection are intentionally rejected by the
25 // library. This example only uses safe end-to-end request headers.
26 let response = request.execute()?;
27
28 println!("manual request to {url}");
29 println!(
30 "status: {} {}",
31 response.status_code, response.reason_phrase
32 );
33 println!("content-type: {:?}", response.header("content-type"));
34 println!("body preview: {}", preview_text(response.body_text()?, 80));
35
36 Ok(())
37}Sourcepub fn if_match(
&mut self,
etag: impl Into<String>,
) -> Result<&mut Self, NanoGetError>
pub fn if_match( &mut self, etag: impl Into<String>, ) -> Result<&mut Self, NanoGetError>
Sets If-Match.
Sourcepub fn if_modified_since(
&mut self,
timestamp: SystemTime,
) -> Result<&mut Self, NanoGetError>
pub fn if_modified_since( &mut self, timestamp: SystemTime, ) -> Result<&mut Self, NanoGetError>
Sets If-Modified-Since using IMF-fixdate formatting.
Examples found in repository?
14fn main() -> Result<(), Box<dyn Error>> {
15 let url = "http://example.com";
16 let mut request = Request::get(url)?.with_redirect_policy(RedirectPolicy::follow(5));
17
18 request.add_header("Accept", "text/html,application/xhtml+xml")?;
19 request.add_header("Cache-Control", "max-age=0")?;
20 request.if_none_match("\"demo-etag\"")?;
21 request.if_modified_since(UNIX_EPOCH + Duration::from_secs(784_111_777))?;
22 request.range_bytes(Some(0), Some(255))?;
23
24 // Protocol-managed headers such as Host and Connection are intentionally rejected by the
25 // library. This example only uses safe end-to-end request headers.
26 let response = request.execute()?;
27
28 println!("manual request to {url}");
29 println!(
30 "status: {} {}",
31 response.status_code, response.reason_phrase
32 );
33 println!("content-type: {:?}", response.header("content-type"));
34 println!("body preview: {}", preview_text(response.body_text()?, 80));
35
36 Ok(())
37}Sourcepub fn if_unmodified_since(
&mut self,
timestamp: SystemTime,
) -> Result<&mut Self, NanoGetError>
pub fn if_unmodified_since( &mut self, timestamp: SystemTime, ) -> Result<&mut Self, NanoGetError>
Sets If-Unmodified-Since using IMF-fixdate formatting.
Sourcepub fn if_range(
&mut self,
value: impl Into<String>,
) -> Result<&mut Self, NanoGetError>
pub fn if_range( &mut self, value: impl Into<String>, ) -> Result<&mut Self, NanoGetError>
Sets If-Range.
Sets an explicit Authorization header for this request.
Manual request-level credentials take precedence over automatic client-level auth helpers.
Sets an explicit Proxy-Authorization header for this request.
Manual request-level credentials take precedence over automatic client-level proxy auth helpers.
Sourcepub fn basic_auth(
&mut self,
username: impl Into<String>,
password: impl Into<String>,
) -> Result<&mut Self, NanoGetError>
pub fn basic_auth( &mut self, username: impl Into<String>, password: impl Into<String>, ) -> Result<&mut Self, NanoGetError>
Encodes username:password as HTTP Basic credentials and stores them in
Authorization.
Examples found in repository?
18fn main() -> Result<(), Box<dyn Error>> {
19 let Some(url) = env::var("NANO_GET_BASIC_AUTH_URL").ok() else {
20 print_setup();
21 return Ok(());
22 };
23
24 let user = env_or_default("NANO_GET_BASIC_AUTH_USER", "demo-user");
25 let pass = env_or_default("NANO_GET_BASIC_AUTH_PASS", "demo-pass");
26
27 let challenge_driven = Client::builder()
28 .basic_auth(user.clone(), pass.clone())
29 .build()
30 .execute(Request::get(&url)?)?;
31
32 let preemptive = Client::builder()
33 .preemptive_basic_auth(user.clone(), pass.clone())
34 .build()
35 .execute(Request::get(&url)?)?;
36
37 let mut request = Request::get(&url)?;
38 request.basic_auth(user, pass)?;
39 let manual = request.execute()?;
40
41 println!("basic-auth example");
42 println!("challenge-driven status: {}", challenge_driven.status_code);
43 println!("preemptive status: {}", preemptive.status_code);
44 println!("request-level override status: {}", manual.status_code);
45
46 Ok(())
47}Sourcepub fn proxy_basic_auth(
&mut self,
username: impl Into<String>,
password: impl Into<String>,
) -> Result<&mut Self, NanoGetError>
pub fn proxy_basic_auth( &mut self, username: impl Into<String>, password: impl Into<String>, ) -> Result<&mut Self, NanoGetError>
Encodes username:password as HTTP Basic credentials and stores them in
Proxy-Authorization.
Examples found in repository?
19fn main() -> Result<(), Box<dyn Error>> {
20 let Some(proxy_url) = env::var("NANO_GET_PROXY_URL").ok() else {
21 print_setup();
22 return Ok(());
23 };
24
25 let target_url = env_or_default("NANO_GET_PROXY_TARGET_URL", "http://example.com");
26 let proxy_user = env_or_default("NANO_GET_PROXY_AUTH_USER", "proxy-user");
27 let proxy_pass = env_or_default("NANO_GET_PROXY_AUTH_PASS", "proxy-pass");
28
29 let mut proxy = ProxyConfig::new(proxy_url)?;
30 proxy.add_header("X-Example-Proxy", "nano-get-demo")?;
31
32 let challenge_driven = Client::builder()
33 .proxy(proxy.clone())
34 .basic_proxy_auth(proxy_user.clone(), proxy_pass.clone())
35 .build()
36 .execute(Request::get(&target_url)?)?;
37
38 let preemptive = Client::builder()
39 .proxy(proxy.clone())
40 .preemptive_basic_proxy_auth(proxy_user.clone(), proxy_pass.clone())
41 .build()
42 .execute(Request::get(&target_url)?)?;
43
44 let mut manual = Request::get(&target_url)?;
45 manual.proxy_basic_auth(proxy_user, proxy_pass)?;
46 let manual_response = Client::builder().proxy(proxy).build().execute(manual)?;
47
48 println!("proxy-and-proxy-auth example");
49 println!("challenge-driven status: {}", challenge_driven.status_code);
50 println!("preemptive status: {}", preemptive.status_code);
51 println!(
52 "request-level override status: {}",
53 manual_response.status_code
54 );
55
56 Ok(())
57}Sourcepub fn range_bytes(
&mut self,
start: Option<u64>,
end: Option<u64>,
) -> Result<&mut Self, NanoGetError>
pub fn range_bytes( &mut self, start: Option<u64>, end: Option<u64>, ) -> Result<&mut Self, NanoGetError>
Sets a Range header for byte-range requests.
Valid forms:
Some(start), Some(end)=>bytes=start-endSome(start), None=>bytes=start-None, Some(end)=>bytes=-end
Examples found in repository?
14fn main() -> Result<(), Box<dyn Error>> {
15 let url = "http://example.com";
16 let mut request = Request::get(url)?.with_redirect_policy(RedirectPolicy::follow(5));
17
18 request.add_header("Accept", "text/html,application/xhtml+xml")?;
19 request.add_header("Cache-Control", "max-age=0")?;
20 request.if_none_match("\"demo-etag\"")?;
21 request.if_modified_since(UNIX_EPOCH + Duration::from_secs(784_111_777))?;
22 request.range_bytes(Some(0), Some(255))?;
23
24 // Protocol-managed headers such as Host and Connection are intentionally rejected by the
25 // library. This example only uses safe end-to-end request headers.
26 let response = request.execute()?;
27
28 println!("manual request to {url}");
29 println!(
30 "status: {} {}",
31 response.status_code, response.reason_phrase
32 );
33 println!("content-type: {:?}", response.header("content-type"));
34 println!("body preview: {}", preview_text(response.body_text()?, 80));
35
36 Ok(())
37}Sourcepub fn execute(&self) -> Result<Response, NanoGetError>
pub fn execute(&self) -> Result<Response, NanoGetError>
Executes this request using Client::default.
Use crate::Client directly when you need explicit client configuration.
Examples found in repository?
14fn main() -> Result<(), Box<dyn Error>> {
15 let url = "http://example.com";
16 let mut request = Request::get(url)?.with_redirect_policy(RedirectPolicy::follow(5));
17
18 request.add_header("Accept", "text/html,application/xhtml+xml")?;
19 request.add_header("Cache-Control", "max-age=0")?;
20 request.if_none_match("\"demo-etag\"")?;
21 request.if_modified_since(UNIX_EPOCH + Duration::from_secs(784_111_777))?;
22 request.range_bytes(Some(0), Some(255))?;
23
24 // Protocol-managed headers such as Host and Connection are intentionally rejected by the
25 // library. This example only uses safe end-to-end request headers.
26 let response = request.execute()?;
27
28 println!("manual request to {url}");
29 println!(
30 "status: {} {}",
31 response.status_code, response.reason_phrase
32 );
33 println!("content-type: {:?}", response.header("content-type"));
34 println!("body preview: {}", preview_text(response.body_text()?, 80));
35
36 Ok(())
37}More examples
18fn main() -> Result<(), Box<dyn Error>> {
19 let Some(url) = env::var("NANO_GET_BASIC_AUTH_URL").ok() else {
20 print_setup();
21 return Ok(());
22 };
23
24 let user = env_or_default("NANO_GET_BASIC_AUTH_USER", "demo-user");
25 let pass = env_or_default("NANO_GET_BASIC_AUTH_PASS", "demo-pass");
26
27 let challenge_driven = Client::builder()
28 .basic_auth(user.clone(), pass.clone())
29 .build()
30 .execute(Request::get(&url)?)?;
31
32 let preemptive = Client::builder()
33 .preemptive_basic_auth(user.clone(), pass.clone())
34 .build()
35 .execute(Request::get(&url)?)?;
36
37 let mut request = Request::get(&url)?;
38 request.basic_auth(user, pass)?;
39 let manual = request.execute()?;
40
41 println!("basic-auth example");
42 println!("challenge-driven status: {}", challenge_driven.status_code);
43 println!("preemptive status: {}", preemptive.status_code);
44 println!("request-level override status: {}", manual.status_code);
45
46 Ok(())
47}