Create new configuration option for redirect preserving authorization header in Agent. Handle new option in Unit
This commit is contained in:
21
src/agent.rs
21
src/agent.rs
@@ -16,6 +16,16 @@ use {
|
|||||||
cookie_store::CookieStore,
|
cookie_store::CookieStore,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Specify the strategy for propagation of authorization headers during Redirects
|
||||||
|
///
|
||||||
|
/// Never is the default strategy and never send authorization headers in Redirects
|
||||||
|
/// SameHost send the authorization header in Redirects only if the host of the Redirect is the same of the previous request, and both use the Https scheme
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum RedirectAuthHeaders {
|
||||||
|
Never,
|
||||||
|
SameHost,
|
||||||
|
}
|
||||||
|
|
||||||
/// Accumulates options towards building an [Agent].
|
/// Accumulates options towards building an [Agent].
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AgentBuilder {
|
pub struct AgentBuilder {
|
||||||
@@ -38,6 +48,7 @@ pub(crate) struct AgentConfig {
|
|||||||
pub timeout_write: Option<Duration>,
|
pub timeout_write: Option<Duration>,
|
||||||
pub timeout: Option<Duration>,
|
pub timeout: Option<Duration>,
|
||||||
pub redirects: u32,
|
pub redirects: u32,
|
||||||
|
pub redirect_auth_headers: RedirectAuthHeaders,
|
||||||
pub user_agent: String,
|
pub user_agent: String,
|
||||||
pub tls_config: Arc<dyn TlsConnector>,
|
pub tls_config: Arc<dyn TlsConnector>,
|
||||||
}
|
}
|
||||||
@@ -221,6 +232,7 @@ impl AgentBuilder {
|
|||||||
timeout_write: None,
|
timeout_write: None,
|
||||||
timeout: None,
|
timeout: None,
|
||||||
redirects: 5,
|
redirects: 5,
|
||||||
|
redirect_auth_headers: RedirectAuthHeaders::Never,
|
||||||
user_agent: format!("ureq/{}", env!("CARGO_PKG_VERSION")),
|
user_agent: format!("ureq/{}", env!("CARGO_PKG_VERSION")),
|
||||||
tls_config: crate::default_tls_config(),
|
tls_config: crate::default_tls_config(),
|
||||||
},
|
},
|
||||||
@@ -445,6 +457,15 @@ impl AgentBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the strategy for propagation of authorization headers in redirects.
|
||||||
|
///
|
||||||
|
/// Defaults to RedirectAuthHeaders::Never.
|
||||||
|
///
|
||||||
|
pub fn set_redirect_auth_headers(mut self, v: RedirectAuthHeaders) -> Self {
|
||||||
|
self.config.redirect_auth_headers = v;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// The user-agent header to associate with all requests from this agent by default.
|
/// The user-agent header to associate with all requests from this agent by default.
|
||||||
///
|
///
|
||||||
/// Defaults to `ureq/[VERSION]`. You can override the user-agent on an individual request by
|
/// Defaults to `ureq/[VERSION]`. You can override the user-agent on an individual request by
|
||||||
|
|||||||
33
src/unit.rs
33
src/unit.rs
@@ -9,6 +9,7 @@ use url::Url;
|
|||||||
#[cfg(feature = "cookies")]
|
#[cfg(feature = "cookies")]
|
||||||
use cookie::Cookie;
|
use cookie::Cookie;
|
||||||
|
|
||||||
|
use crate::agent::RedirectAuthHeaders;
|
||||||
use crate::body::{self, BodySize, Payload, SizedReader};
|
use crate::body::{self, BodySize, Payload, SizedReader};
|
||||||
use crate::error::{Error, ErrorKind};
|
use crate::error::{Error, ErrorKind};
|
||||||
use crate::header;
|
use crate::header;
|
||||||
@@ -353,6 +354,17 @@ fn connect_socket(unit: &Unit, hostname: &str, use_pooled: bool) -> Result<(Stre
|
|||||||
Ok((stream?, false))
|
Ok((stream?, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn can_propagate_authorization_on_redirect(unit: &Unit, previous: &[String]) -> bool {
|
||||||
|
if let RedirectAuthHeaders::SameHost = unit.agent.config.redirect_auth_headers {
|
||||||
|
let host_s = unit.url.host_str().unwrap();
|
||||||
|
let prev_url = Url::parse(&previous[0]).unwrap();
|
||||||
|
let prev_host = prev_url.host_str().unwrap();
|
||||||
|
host_s == prev_host && prev_url.scheme() == "https" && unit.url.scheme() == "https"
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Send request line + headers (all up until the body).
|
/// Send request line + headers (all up until the body).
|
||||||
#[allow(clippy::write_with_newline)]
|
#[allow(clippy::write_with_newline)]
|
||||||
fn send_prelude(unit: &Unit, stream: &mut Stream, previous: &[String]) -> io::Result<()> {
|
fn send_prelude(unit: &Unit, stream: &mut Stream, previous: &[String]) -> io::Result<()> {
|
||||||
@@ -393,28 +405,13 @@ fn send_prelude(unit: &Unit, stream: &mut Stream, previous: &[String]) -> io::Re
|
|||||||
if !header::has_header(&unit.headers, "accept") {
|
if !header::has_header(&unit.headers, "accept") {
|
||||||
prelude.write_header("Accept", "*/*")?;
|
prelude.write_header("Accept", "*/*")?;
|
||||||
}
|
}
|
||||||
//Preserve Authorization in Same Host redirections
|
|
||||||
let host_s = unit.url.host_str().unwrap();
|
|
||||||
let preserve_auth = if !previous.is_empty() {
|
let preserve_auth = if !previous.is_empty() {
|
||||||
let prev_url = Url::parse(&previous[0]).unwrap();
|
can_propagate_authorization_on_redirect(unit, previous)
|
||||||
if let Some(prev_host) = prev_url.host_str() {
|
|
||||||
if host_s == prev_host {
|
|
||||||
if prev_url.scheme() == unit.url.scheme() {
|
|
||||||
let port = unit.url.port().unwrap_or(scheme_default);
|
|
||||||
let prev_port = prev_url.port().unwrap_or(scheme_default);
|
|
||||||
port == prev_port
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
true //Not in redirection
|
true //Not in redirection
|
||||||
};
|
};
|
||||||
|
|
||||||
// other headers
|
// other headers
|
||||||
for header in &unit.headers {
|
for header in &unit.headers {
|
||||||
if preserve_auth || !header.is_name("Authorization") {
|
if preserve_auth || !header.is_name("Authorization") {
|
||||||
|
|||||||
Reference in New Issue
Block a user