Create new configuration option for redirect preserving authorization header in Agent. Handle new option in Unit

This commit is contained in:
llde
2021-12-10 17:56:44 +01:00
committed by Martin Algesten
parent 38ad90307d
commit 653f791638
2 changed files with 36 additions and 18 deletions

View File

@@ -16,6 +16,16 @@ use {
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].
#[derive(Debug)]
pub struct AgentBuilder {
@@ -38,6 +48,7 @@ pub(crate) struct AgentConfig {
pub timeout_write: Option<Duration>,
pub timeout: Option<Duration>,
pub redirects: u32,
pub redirect_auth_headers: RedirectAuthHeaders,
pub user_agent: String,
pub tls_config: Arc<dyn TlsConnector>,
}
@@ -221,6 +232,7 @@ impl AgentBuilder {
timeout_write: None,
timeout: None,
redirects: 5,
redirect_auth_headers: RedirectAuthHeaders::Never,
user_agent: format!("ureq/{}", env!("CARGO_PKG_VERSION")),
tls_config: crate::default_tls_config(),
},
@@ -445,6 +457,15 @@ impl AgentBuilder {
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.
///
/// Defaults to `ureq/[VERSION]`. You can override the user-agent on an individual request by

View File

@@ -9,6 +9,7 @@ use url::Url;
#[cfg(feature = "cookies")]
use cookie::Cookie;
use crate::agent::RedirectAuthHeaders;
use crate::body::{self, BodySize, Payload, SizedReader};
use crate::error::{Error, ErrorKind};
use crate::header;
@@ -353,6 +354,17 @@ fn connect_socket(unit: &Unit, hostname: &str, use_pooled: bool) -> Result<(Stre
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).
#[allow(clippy::write_with_newline)]
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") {
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 prev_url = Url::parse(&previous[0]).unwrap();
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
}
can_propagate_authorization_on_redirect(unit, previous)
} else {
true //Not in redirection
};
// other headers
for header in &unit.headers {
if preserve_auth || !header.is_name("Authorization") {