I'm writing my own implementation of parsing S3 requests and am working on handling PutObject.
async fn handle_request(
State(state): State<Arc<AppState>>,
ConnectInfo(addr): ConnectInfo<SocketAddr>,
req: Request<Body>,
) -> Response {
let req =
req.map(|body| reqwest::Body::wrap_stream(SyncStream::new(body.into_data_stream())));
let mut data = S3Data::new();
data.req = req;
data.req.headers_mut().insert(
"x-real-ip",
reqwest::header::HeaderValue::from_str(&addr.ip().to_string()).unwrap(),
);
match state.filter_chain.run_filters(&mut data).await {
Ok(_) => {}
Err(e) => {
return e.into_response();
}
}
This the req type I get in my handler and I'm trying to make it into a S3Data struct like below
#[async_trait]
pub trait Filter: Send + Sync {
async fn handle(&self, data: &mut S3Data) -> Result<(), S3Error>;
}
#[derive(Debug)]
pub struct S3Data {
pub req: axum::http::Request<reqwest::Body>,
...
}
I pass the S3Data struct through a series of filters to validate the request and return appropriate error if there is one. However, I can't use the axum::body::Body type as it does not implement Sync
I also do not want to use Bytes as I believe it buffers the entire body into memory and would drastically slow down handling a PutObject operation with large files. Do I need to make my own custom struct here that implements the traits needed? I'm eventually calling this fn below so I need some way of translating the Body into a aws_sdk_s3::primitives::ByteStream
async fn save_file(&self, bucket: &str, key: &str, data: ByteStream) -> Result<(), S3Error> {
let response = self
.s3_client
.put_object()
.bucket(bucket)
.key(key)
.body(data)
.send()
.await
.map_err(|_| S3Error::InternalError)?;
Ok(())
}