manual redirect handling
This commit is contained in:
parent
bbb4a17263
commit
a53d874a12
2 changed files with 17 additions and 3 deletions
|
|
@ -28,7 +28,7 @@ use dyn_clone::{clone_trait_object, DynClone};
|
||||||
use moka::future::Cache;
|
use moka::future::Cache;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use reqwest::Request;
|
use reqwest::{redirect::Policy, Client, Request};
|
||||||
use reqwest_middleware::{ClientWithMiddleware, RequestBuilder};
|
use reqwest_middleware::{ClientWithMiddleware, RequestBuilder};
|
||||||
use rsa::{pkcs8::DecodePrivateKey, RsaPrivateKey};
|
use rsa::{pkcs8::DecodePrivateKey, RsaPrivateKey};
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
|
|
@ -58,9 +58,10 @@ pub struct FederationConfig<T: Clone> {
|
||||||
/// [crate::fetch::object_id::ObjectId] for more details.
|
/// [crate::fetch::object_id::ObjectId] for more details.
|
||||||
#[builder(default = "20")]
|
#[builder(default = "20")]
|
||||||
pub(crate) http_fetch_limit: u32,
|
pub(crate) http_fetch_limit: u32,
|
||||||
#[builder(default = "reqwest::Client::default().into()")]
|
#[builder(default = "default_client()")]
|
||||||
/// HTTP client used for all outgoing requests. Middleware can be used to add functionality
|
/// HTTP client used for all outgoing requests. Middleware can be used to add functionality
|
||||||
/// like log tracing or retry of failed requests.
|
/// like log tracing or retry of failed requests.
|
||||||
|
/// Redirects should be disabled to prevent an attacker from accessing local addresses.
|
||||||
pub(crate) client: ClientWithMiddleware,
|
pub(crate) client: ClientWithMiddleware,
|
||||||
/// Run library in debug mode. This allows usage of http and localhost urls. It also sends
|
/// Run library in debug mode. This allows usage of http and localhost urls. It also sends
|
||||||
/// outgoing activities synchronously, not in background thread. This helps to make tests
|
/// outgoing activities synchronously, not in background thread. This helps to make tests
|
||||||
|
|
@ -416,6 +417,14 @@ impl<T: Clone> FederationMiddleware<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_client() -> ClientWithMiddleware {
|
||||||
|
Client::builder()
|
||||||
|
.redirect(Policy::none())
|
||||||
|
.build()
|
||||||
|
.unwrap_or_else(|_| Client::default())
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[allow(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use crate::{
|
||||||
FEDERATION_CONTENT_TYPE,
|
FEDERATION_CONTENT_TYPE,
|
||||||
};
|
};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use http::{HeaderValue, StatusCode};
|
use http::{header::LOCATION, HeaderValue, StatusCode};
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
@ -132,6 +132,11 @@ async fn fetch_object_http_with_accept<T: Clone, Kind: DeserializeOwned>(
|
||||||
req.send().await?
|
req.send().await?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Some(location) = res.headers().get(LOCATION) {
|
||||||
|
let location: Url = location.to_str().unwrap().parse()?;
|
||||||
|
return Box::pin(fetch_object_http_with_accept(&location, data, content_type)).await;
|
||||||
|
}
|
||||||
|
|
||||||
if res.status() == StatusCode::GONE {
|
if res.status() == StatusCode::GONE {
|
||||||
return Err(Error::ObjectDeleted(url.clone()));
|
return Err(Error::ObjectDeleted(url.clone()));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue