use std::collections::HashMap;
use bytes::Bytes;
use crate::http::requests::http_request_with_headers;
use crate::s3::client::S3Client;
use crate::s3::client_config::S3ClientConfig;
use crate::LakestreamError;
async fn handle_redirect(s3_client: &S3Client, new_region: &str) -> S3Client {
let config = s3_client.config();
let bucket_name = config.bucket_name();
let credentials = config.credentials().clone();
let endpoint_url = config.endpoint_url();
let s3_client_config =
S3ClientConfig::new(credentials, bucket_name, endpoint_url, new_region);
S3Client::new(s3_client_config)
}
pub async fn http_with_redirect_handling<F>(
s3_client: &S3Client,
generate_headers: F,
method: &str,
) -> Result<
(Bytes, Option<S3Client>, u16, HashMap<String, String>),
LakestreamError,
>
where
F: Fn(&mut S3Client) -> Result<HashMap<String, String>, LakestreamError>,
{
let mut current_s3_client = s3_client.clone();
loop {
let headers = generate_headers(&mut current_s3_client)?;
let result = http_request_with_headers(
¤t_s3_client.url(),
&headers,
method,
)
.await;
match result {
Ok((body_bytes, status_code, response_headers)) => {
if status_code == 301 {
if let Some(new_region) =
response_headers.get("x-amz-bucket-region")
{
current_s3_client =
handle_redirect(¤t_s3_client, new_region)
.await;
} else {
let error = "Error: Redirect without \
x-amz-bucket-region header";
return Err(LakestreamError::from(error));
}
} else {
if status_code == 403 {
let url = current_s3_client.url();
return Err(LakestreamError::AccessDenied(
url.to_string(),
));
}
return Ok((
body_bytes,
if current_s3_client.region() != s3_client.region() {
Some(current_s3_client)
} else {
None
},
status_code,
response_headers,
));
}
}
Err(e) => return Err(LakestreamError::from(e)),
}
}
}