-
Notifications
You must be signed in to change notification settings - Fork 194
feature: expose redirect policy through extension #583
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feature: expose redirect policy through extension #583
Conversation
@@ -197,7 +197,7 @@ impl<ReqBody, ResBody, S, P> Service<Request<ReqBody>> for FollowRedirect<S, P> | |||
where | |||
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone, | |||
ReqBody: Body + Default, | |||
P: Policy<ReqBody, S::Error> + Clone, | |||
P: Policy<ReqBody, S::Error> + Clone + Send + Sync + 'static, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be considered breaking changes, since some types might not fit the bounds.
Can we insert a custom extension without the need to change this layer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what you mean by layer ? the tower middleware Layer
?
The extra constraints come from the signature of http::extensions::Extensions
pub fn insert<T: Clone + Send + Sync + 'static>(&mut self, val: T) -> Option<T>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One way to avoid the breaking change would be something like:
trait MaybeAddExtension {
fn add_policy_ext<ResBody>(&self, _res: &mut Response<ResBody>) {}
}
impl<T> MaybeAddExtension for T
where
T: Clone + Send + Sync + 'static,
{
fn add_policy_ext<ResBody>(&self, res: &mut Response<ResBody>) {
res.extensions_mut().insert(FollowedPolicy(self.clone()));
}
}
and then we can have
- P: Policy<ReqBody, S::Error> + Clone,
+ P: Policy<ReqBody, S::Error> + Clone + MaybeAddExtension,
res.extensions_mut().insert(RequestUri(this.uri.clone()));
+ this.policy.add_policy_ext(&mut res);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You'd still be adding a bound where there wasn't one before, it would be exactly the same breaking change. The problem is somebody could have implemented a custom policy that's not Send
or not Sync
, and passed that to with_policy
. The change to this line would then result in FollowRedirect<_, CustomPolicy>
no longer implementing Service
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh you're right, somehow I mistakenly thought that the default empty implementation would be generated for non-Sync/Send policies.
So is the only way to avoid the breaking change to define a second layer variant that adds the extension?
This adds a
FollowedPolicy
extension for theFollowRedirect
middleware that exposes the policy struct to the response.Motivation
Currently there is no way to inspect the URLs (and status codes) that a redirected response took, as there is no way to "get back" the redirect policy struct from
follow_redirect::ResponseFuture
.Custom redirect policies might have useful state that the user wants to access once the request completes. A typical use case would be to log the urls and status codes that have been traversed, which is already necessary for example to avoid loops.
This implements part of the modifications suggested in #404 as I understand it. It is also required to implement seanmonstar/reqwest#2606
Solution
Implement a
http::Extensions::Extension
that stores a copy of thefollow_redirect::policy::Policy
struct that was run on the last request of the redirect chain.Downsides
Currently this does another
clone()
of the policy struct for each new request