use std::{
io,
pin::Pin,
task::{Context, Poll},
};
use async_http_codec::{BodyDecodeState, ResponseHead};
use futures::AsyncRead;
use http::HeaderValue;
use crate::Transport;
use super::error::HttpError;
pub struct ResponseBodyInner {
state: BodyDecodeState,
transport: Option<Transport>,
error: Option<HttpError>,
}
impl ResponseBodyInner {
pub(crate) fn new(transport: Transport, head: &ResponseHead) -> Result<Self, HttpError> {
let state =
BodyDecodeState::from_headers(head.headers()).map_err(|_err| HttpError::UnsupportedTransferEncoding(HeaderValue::from_static("TODO")))?;
Ok(Self {
state,
transport: Some(transport),
error: None,
})
}
#[cfg(feature = "websocket")]
pub(crate) fn into_inner(self) -> Result<(BodyDecodeState, Transport), HttpError> {
let ResponseBodyInner { state, transport, error } = self;
if let Some(err) = error {
return Err(err);
}
Ok((state, transport.unwrap()))
}
}
impl AsyncRead for ResponseBodyInner {
fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
if let Some(err) = &self.error {
return Poll::Ready(Err(err.clone().into()));
}
let mut transport = self.transport.take().unwrap();
match self.state.poll_read(&mut transport, cx, buf) {
Poll::Ready(Err(err)) => {
self.error = Some(HttpError::IoError(err.into()));
Poll::Ready(Err(self.error.clone().unwrap().into()))
}
p => {
self.transport = Some(transport);
p
}
}
}
}