From 3f297cfa922825561a3c556221da8acc22b97848 Mon Sep 17 00:00:00 2001 From: Luca BRUNO Date: Thu, 17 Apr 2025 16:08:26 +0200 Subject: [PATCH] follow_redirect: expose previous and next request methods This augments follow-redirect `Attempt` in order to expose two relevant HTTP methods during redirects: - the method for the original/previous request - the method to be performed on the next request upon following a redirection This allows consumers to write policies based on both previous and next requests methods. --- tower-http/src/follow_redirect/mod.rs | 3 +++ tower-http/src/follow_redirect/policy/and.rs | 4 +++- .../follow_redirect/policy/filter_credentials.rs | 6 +++++- tower-http/src/follow_redirect/policy/limited.rs | 6 +++++- tower-http/src/follow_redirect/policy/mod.rs | 14 +++++++++++++- tower-http/src/follow_redirect/policy/or.rs | 4 +++- .../src/follow_redirect/policy/same_origin.rs | 6 +++++- 7 files changed, 37 insertions(+), 6 deletions(-) diff --git a/tower-http/src/follow_redirect/mod.rs b/tower-http/src/follow_redirect/mod.rs index 516fabf7..9258225c 100644 --- a/tower-http/src/follow_redirect/mod.rs +++ b/tower-http/src/follow_redirect/mod.rs @@ -257,6 +257,7 @@ where let mut res = ready!(this.future.as_mut().poll(cx)?); res.extensions_mut().insert(RequestUri(this.uri.clone())); + let previous_method = &this.method.clone(); match res.status() { StatusCode::MOVED_PERMANENTLY | StatusCode::FOUND => { // User agents MAY change the request method from POST to GET @@ -295,7 +296,9 @@ where let attempt = Attempt { status: res.status(), + next_method: &this.method, location: &location, + previous_method, previous: this.uri, }; match this.policy.redirect(&attempt)? { diff --git a/tower-http/src/follow_redirect/policy/and.rs b/tower-http/src/follow_redirect/policy/and.rs index 69d2b7da..92d239d0 100644 --- a/tower-http/src/follow_redirect/policy/and.rs +++ b/tower-http/src/follow_redirect/policy/and.rs @@ -45,7 +45,7 @@ where #[cfg(test)] mod tests { use super::*; - use http::Uri; + use http::{Method, Uri}; struct Taint

{ policy: P, @@ -75,7 +75,9 @@ mod tests { fn redirect() { let attempt = Attempt { status: Default::default(), + next_method: &Method::GET, location: &Uri::from_static("*"), + previous_method: &Method::GET, previous: &Uri::from_static("*"), }; diff --git a/tower-http/src/follow_redirect/policy/filter_credentials.rs b/tower-http/src/follow_redirect/policy/filter_credentials.rs index fea80f11..7b3b9f1e 100644 --- a/tower-http/src/follow_redirect/policy/filter_credentials.rs +++ b/tower-http/src/follow_redirect/policy/filter_credentials.rs @@ -106,7 +106,7 @@ impl Policy for FilterCredentials { #[cfg(test)] mod tests { use super::*; - use http::Uri; + use http::{Method, Uri}; #[test] fn works() { @@ -126,7 +126,9 @@ mod tests { let attempt = Attempt { status: Default::default(), + next_method: &Method::GET, location: &same_origin, + previous_method: &Method::GET, previous: request.uri(), }; assert!(Policy::<(), ()>::redirect(&mut policy, &attempt) @@ -143,7 +145,9 @@ mod tests { let attempt = Attempt { status: Default::default(), + next_method: &Method::GET, location: &cross_origin, + previous_method: &Method::GET, previous: request.uri(), }; assert!(Policy::<(), ()>::redirect(&mut policy, &attempt) diff --git a/tower-http/src/follow_redirect/policy/limited.rs b/tower-http/src/follow_redirect/policy/limited.rs index a81b0d79..08401264 100644 --- a/tower-http/src/follow_redirect/policy/limited.rs +++ b/tower-http/src/follow_redirect/policy/limited.rs @@ -36,7 +36,7 @@ impl Policy for Limited { #[cfg(test)] mod tests { - use http::{Request, Uri}; + use http::{Method, Request, Uri}; use super::*; @@ -51,7 +51,9 @@ mod tests { let attempt = Attempt { status: Default::default(), + next_method: &Method::GET, location: &uri, + previous_method: &Method::GET, previous: &uri, }; assert!(Policy::<(), ()>::redirect(&mut policy, &attempt) @@ -64,7 +66,9 @@ mod tests { let attempt = Attempt { status: Default::default(), + next_method: &Method::GET, location: &uri, + previous_method: &Method::GET, previous: &uri, }; assert!(Policy::<(), ()>::redirect(&mut policy, &attempt) diff --git a/tower-http/src/follow_redirect/policy/mod.rs b/tower-http/src/follow_redirect/policy/mod.rs index 8e5d39ce..fec62241 100644 --- a/tower-http/src/follow_redirect/policy/mod.rs +++ b/tower-http/src/follow_redirect/policy/mod.rs @@ -18,7 +18,7 @@ pub use self::{ same_origin::SameOrigin, }; -use http::{uri::Scheme, Request, StatusCode, Uri}; +use http::{uri::Scheme, Method, Request, StatusCode, Uri}; /// Trait for the policy on handling redirection responses. /// @@ -198,7 +198,9 @@ pub type Standard = And; /// A type that holds information on a redirection attempt. pub struct Attempt<'a> { pub(crate) status: StatusCode, + pub(crate) next_method: &'a Method, pub(crate) location: &'a Uri, + pub(crate) previous_method: &'a Method, pub(crate) previous: &'a Uri, } @@ -208,11 +210,21 @@ impl<'a> Attempt<'a> { self.status } + /// Returns the method for the next request, after applying redirection logic. + pub fn next_method(&self) -> &Method { + self.next_method + } + /// Returns the destination URI of the redirection. pub fn location(&self) -> &'a Uri { self.location } + /// Returns the method for the previous request, before redirection. + pub fn previous_method(&self) -> &Method { + self.previous_method + } + /// Returns the URI of the original request. pub fn previous(&self) -> &'a Uri { self.previous diff --git a/tower-http/src/follow_redirect/policy/or.rs b/tower-http/src/follow_redirect/policy/or.rs index 858e57bd..8c96493c 100644 --- a/tower-http/src/follow_redirect/policy/or.rs +++ b/tower-http/src/follow_redirect/policy/or.rs @@ -45,7 +45,7 @@ where #[cfg(test)] mod tests { use super::*; - use http::Uri; + use http::{Method, Uri}; struct Taint

{ policy: P, @@ -75,7 +75,9 @@ mod tests { fn redirect() { let attempt = Attempt { status: Default::default(), + next_method: &Method::GET, location: &Uri::from_static("*"), + previous_method: &Method::GET, previous: &Uri::from_static("*"), }; diff --git a/tower-http/src/follow_redirect/policy/same_origin.rs b/tower-http/src/follow_redirect/policy/same_origin.rs index cf7b7b19..b82e7562 100644 --- a/tower-http/src/follow_redirect/policy/same_origin.rs +++ b/tower-http/src/follow_redirect/policy/same_origin.rs @@ -33,7 +33,7 @@ impl Policy for SameOrigin { #[cfg(test)] mod tests { use super::*; - use http::{Request, Uri}; + use http::{Method, Request, Uri}; #[test] fn works() { @@ -48,7 +48,9 @@ mod tests { let attempt = Attempt { status: Default::default(), + next_method: &Method::GET, location: &same_origin, + previous_method: &Method::GET, previous: request.uri(), }; assert!(Policy::<(), ()>::redirect(&mut policy, &attempt) @@ -60,7 +62,9 @@ mod tests { let attempt = Attempt { status: Default::default(), + next_method: &Method::GET, location: &cross_origin, + previous_method: &Method::GET, previous: request.uri(), }; assert!(Policy::<(), ()>::redirect(&mut policy, &attempt)