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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
use crate::io::Text;
use crate::{Metrics, Error};
use futures_io::AsyncRead;
use http::{Response, Uri};
use std::fs::File;
use std::io::{self, Read, Write};
use std::path::Path;
/// Provides extension methods for working with HTTP responses.
pub trait ResponseExt<T> {
/// Get the effective URI of this response. This value differs from the
/// original URI provided when making the request if at least one redirect
/// was followed.
///
/// This information is only available if populated by the HTTP client that
/// produced the response.
fn effective_uri(&self) -> Option<&Uri>;
/// If request metrics are enabled for this particular transfer, return a
/// metrics object containing a live view of currently available data.
///
/// By default metrics are disabled and `None` will be returned. To enable
/// metrics for a single request you can use
/// [`RequestExt::metrics`](crate::RequestBuilderExt::metrics), or to enable
/// it client-wide, you can use
/// [`HttpClientBuilder::metrics`](crate::HttpClientBuilder::metrics).
fn metrics(&self) -> Option<&Metrics>;
/// Copy the response body into a writer.
///
/// Returns the number of bytes that were written.
fn copy_to(&mut self, writer: impl Write) -> io::Result<u64>
where
T: Read;
/// Write the response body to a file.
///
/// This method makes it convenient to download a file using a GET request
/// and write it to a file synchronously in a single chain of calls.
///
/// Returns the number of bytes that were written.
///
/// # Examples
///
/// ```no_run
/// use isahc::prelude::*;
///
/// isahc::get("https://httpbin.org/image/jpeg")?
/// .copy_to_file("myimage.jpg")?;
/// # Ok::<(), isahc::Error>(())
/// ```
fn copy_to_file(&mut self, path: impl AsRef<Path>) -> io::Result<u64>
where
T: Read,
{
File::create(path).and_then(|f| self.copy_to(f))
}
/// Get the response body as a string.
///
/// This method consumes the entire response body stream and can only be
/// called once, unless you can rewind this response body.
///
/// # Examples
///
/// ```no_run
/// use isahc::prelude::*;
///
/// let text = isahc::get("https://example.org")?.text()?;
/// println!("{}", text);
/// # Ok::<(), isahc::Error>(())
/// ```
fn text(&mut self) -> Result<String, Error>
where
T: Read;
/// Get the response body as a string asynchronously.
///
/// This method consumes the entire response body stream and can only be
/// called once, unless you can rewind this response body.
fn text_async(&mut self) -> Text<'_, T>
where
T: AsyncRead + Unpin;
/// Deserialize the response body as JSON into a given type.
///
/// This method requires the `json` feature to be enabled.
///
/// # Examples
///
/// ```no_run
/// use isahc::prelude::*;
/// use serde_json::Value;
///
/// let json: Value = isahc::get("https://httpbin.org/json")?.json()?;
/// println!("author: {}", json["slideshow"]["author"]);
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
#[cfg(feature = "json")]
fn json<D>(&mut self) -> Result<D, serde_json::Error>
where
D: serde::de::DeserializeOwned,
T: Read;
}
impl<T> ResponseExt<T> for Response<T> {
fn effective_uri(&self) -> Option<&Uri> {
self.extensions().get::<EffectiveUri>().map(|v| &v.0)
}
fn metrics(&self) -> Option<&Metrics> {
self.extensions().get()
}
fn copy_to(&mut self, mut writer: impl Write) -> io::Result<u64>
where
T: Read,
{
io::copy(self.body_mut(), &mut writer)
}
fn text(&mut self) -> Result<String, Error>
where
T: Read,
{
let mut s = String::default();
self.body_mut().read_to_string(&mut s)?;
Ok(s)
}
fn text_async(&mut self) -> Text<'_, T>
where
T: AsyncRead + Unpin,
{
Text::new(self.body_mut())
}
#[cfg(feature = "json")]
fn json<D>(&mut self) -> Result<D, serde_json::Error>
where
D: serde::de::DeserializeOwned,
T: Read,
{
serde_json::from_reader(self.body_mut())
}
}
pub(crate) struct EffectiveUri(pub(crate) Uri);