Skip to content

Commit 5159862

Browse files
fix: store history in an ext instead of Response struct
1 parent 8188ec6 commit 5159862

File tree

3 files changed

+37
-10
lines changed

3 files changed

+37
-10
lines changed

src/async_impl/client.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use crate::dns::{gai::GaiResolver, DnsResolverWithOverrides, DynResolver, Resolv
3030
use crate::error::{self, BoxError};
3131
use crate::into_url::try_uri;
3232
use crate::redirect::{self, remove_sensitive_headers};
33+
use crate::response::History;
3334
#[cfg(feature = "__rustls")]
3435
use crate::tls::CertificateRevocationList;
3536
#[cfg(feature = "__tls")]
@@ -2851,7 +2852,7 @@ impl Future for PendingRequest {
28512852
}
28522853

28532854
loop {
2854-
let res = match self.as_mut().in_flight().get_mut() {
2855+
let mut res = match self.as_mut().in_flight().get_mut() {
28552856
ResponseFuture::Default(r) => match Pin::new(r).poll(cx) {
28562857
Poll::Ready(Err(e)) => {
28572858
#[cfg(feature = "http2")]
@@ -3032,10 +3033,12 @@ impl Future for PendingRequest {
30323033
}
30333034
}
30343035

3036+
res.extensions_mut()
3037+
.insert(History(mem::take(&mut self.urls)));
3038+
30353039
let res = Response::new(
30363040
res,
30373041
self.url.clone(),
3038-
mem::take(&mut self.urls),
30393042
self.client.accepts,
30403043
self.total_timeout.take(),
30413044
self.read_timeout,

src/async_impl/response.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use super::decoder::{Accepts, Decoder};
1919
use crate::async_impl::body::ResponseBody;
2020
#[cfg(feature = "cookies")]
2121
use crate::cookie;
22+
use crate::response::History;
2223

2324
#[cfg(feature = "charset")]
2425
use encoding_rs::{Encoding, UTF_8};
@@ -31,14 +32,12 @@ pub struct Response {
3132
// Boxed to save space (11 words to 1 word), and it's not accessed
3233
// frequently internally.
3334
url: Box<Url>,
34-
history: Vec<Url>,
3535
}
3636

3737
impl Response {
3838
pub(super) fn new(
3939
res: hyper::Response<ResponseBody>,
4040
url: Url,
41-
history: Vec<Url>,
4241
accepts: Accepts,
4342
total_timeout: Option<Pin<Box<Sleep>>>,
4443
read_timeout: Option<Duration>,
@@ -54,7 +53,6 @@ impl Response {
5453
Response {
5554
res,
5655
url: Box::new(url),
57-
history,
5856
}
5957
}
6058

@@ -122,14 +120,18 @@ impl Response {
122120
/// Get all the intermediate `Url`s traversed by redirects.
123121
#[inline]
124122
pub fn history(&self) -> &[Url] {
125-
&self.history
123+
&self
124+
.extensions()
125+
.get::<History>()
126+
.map(|h| &h.0)
127+
.expect("history extension")
126128
}
127129

128130
/// Get all the `Url`s, in sequential order, that were requested,
129131
/// including any redirects and the final url.
130132
#[inline]
131133
pub fn all_urls(&self) -> impl Iterator<Item = &Url> {
132-
self.history
134+
self.history()
133135
.iter()
134136
.chain(std::iter::once(self.url.as_ref()))
135137
}
@@ -488,11 +490,11 @@ impl<T: Into<Body>> From<http::Response<T>> for Response {
488490
.remove::<ResponseUrl>()
489491
.unwrap_or_else(|| ResponseUrl(Url::parse("http://no.url.provided.local").unwrap()));
490492
let url = url.0;
493+
parts.extensions.get_or_insert_default::<History>();
491494
let res = hyper::Response::from_parts(parts, decoder);
492495
Response {
493496
res,
494497
url: Box::new(url),
495-
history: vec![],
496498
}
497499
}
498500
}

src/response.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,61 @@ use url::Url;
33
#[derive(Debug, Clone, PartialEq)]
44
pub(crate) struct ResponseUrl(pub Url);
55

6+
/// Response [`Extensions`][http::Extensions] value that represents intermediate `Url`s traversed by redirects
7+
#[derive(Debug, Clone, Default, PartialEq)]
8+
pub(crate) struct History(pub Vec<Url>);
9+
610
/// Extension trait for http::response::Builder objects
711
///
812
/// Allows the user to add a `Url` to the http::Response
913
pub trait ResponseBuilderExt {
1014
/// A builder method for the `http::response::Builder` type that allows the user to add a `Url`
1115
/// to the `http::Response`
1216
fn url(self, url: Url) -> Self;
17+
18+
/// A builder method for the `http::response::Builder` type that allows the user to add redirect history
19+
/// to the `http::Response`
20+
fn history(self, history: Vec<Url>) -> Self;
1321
}
1422

1523
impl ResponseBuilderExt for http::response::Builder {
1624
fn url(self, url: Url) -> Self {
1725
self.extension(ResponseUrl(url))
1826
}
27+
28+
fn history(self, history: Vec<Url>) -> Self {
29+
self.extension(History(history))
30+
}
1931
}
2032

2133
#[cfg(test)]
2234
mod tests {
23-
use super::{ResponseBuilderExt, ResponseUrl};
35+
use super::{History, ResponseBuilderExt, ResponseUrl};
2436
use http::response::Builder;
2537
use url::Url;
2638

2739
#[test]
2840
fn test_response_builder_ext() {
29-
let url = Url::parse("http://example.com").unwrap();
41+
let history = vec![
42+
Url::parse("http://initial.com").unwrap(),
43+
Url::parse("http://intermediate.com").unwrap(),
44+
];
45+
let url = Url::parse("http://final.com").unwrap();
3046
let response = Builder::new()
3147
.status(200)
3248
.url(url.clone())
49+
.history(history.clone())
3350
.body(())
3451
.unwrap();
3552

3653
assert_eq!(
3754
response.extensions().get::<ResponseUrl>(),
3855
Some(&ResponseUrl(url))
3956
);
57+
58+
assert_eq!(
59+
response.extensions().get::<History>(),
60+
Some(&History(history))
61+
);
4062
}
4163
}

0 commit comments

Comments
 (0)