use crate::socket::Socket;
use crate::{Request, Response};
use bytes::Bytes;
use h2::client;
use http::Version;
use std::time::Duration;
pub(crate) async fn send_h2_request(
socket: Socket,
request: &Request,
_timeout: Option<Duration>,
) -> crate::Result<Response> {
let _read_timeout = socket.read_timeout;
let _write_timeout = socket.write_timeout;
let (client, h2_conn) = client::handshake(socket.inner)
.await
.map_err(|e| crate::errors::Error::Other(format!("HTTP/2 handshake failed: {}", e)))?;
tokio::spawn(async {
h2_conn.await.unwrap_or_default();
});
let mut client = client
.ready()
.await
.map_err(|e| crate::errors::Error::Other(format!("HTTP/2 client not ready: {}", e)))?;
let mut h2_request = http::Request::builder()
.method(request.method())
.uri(request.uri())
.version(Version::HTTP_2);
for (key, value) in request.headers().iter() {
if key == http::header::CONNECTION
|| key == http::header::TRANSFER_ENCODING
|| key == http::header::UPGRADE
|| key.as_str().to_lowercase() == "keep-alive"
|| key.as_str().to_lowercase() == "proxy-connection"
{
continue;
}
h2_request = h2_request.header(key, value);
}
let body_bytes = request.body().map(|b| b.as_ref()).unwrap_or(&[]);
let h2_request = h2_request
.body(())
.map_err(|e| crate::errors::Error::Other(format!("Failed to build HTTP/2 request: {}", e)))?;
let (response_future, mut send_stream) =
client
.send_request(h2_request, body_bytes.is_empty())
.map_err(|e| crate::errors::Error::Other(format!("Failed to send HTTP/2 request: {}", e)))?;
if !body_bytes.is_empty() {
send_stream
.send_data(Bytes::copy_from_slice(body_bytes), true)
.map_err(|e| crate::errors::Error::Other(format!("Failed to send HTTP/2 body: {}", e)))?;
}
let h2_response = response_future.await.map_err(|e| {
crate::errors::Error::Other(format!("Failed to receive HTTP/2 response: {}", e))
})?;
let status = h2_response.status();
let headers = h2_response.headers().clone();
let mut body_stream = h2_response.into_body();
let mut body = Vec::new();
while let Some(chunk_result) = body_stream.data().await {
let chunk = chunk_result.map_err(|e| {
crate::errors::Error::Other(format!("Failed to read HTTP/2 body chunk: {}", e))
})?;
body.extend_from_slice(&chunk);
body_stream
.flow_control()
.release_capacity(chunk.len())
.map_err(|e| crate::errors::Error::Other(format!("Failed to release flow control: {}", e)))?;
}
let mut response_builder = http::Response::builder()
.status(status)
.version(Version::HTTP_2);
for (key, value) in headers.iter() {
response_builder = response_builder.header(key, value);
}
let http_response = response_builder
.body(Bytes::from(body))
.map_err(|e| crate::errors::Error::Other(format!("Failed to build response: {}", e)))?;
let response: Response = http_response.into();
Ok(response)
}