use crate::codec::http_framed_read::HttpFramedJoinContinuationRead;
use crate::hpack;
use crate::result;
use crate::solicit::frame::HttpFrameDecoded;
use crate::solicit::frame::{HeadersDecodedFrame, HttpFrame};
use crate::solicit::stream_id::StreamId;
use crate::ErrorCode;
use crate::Header;
use crate::Headers;
use futures::task::Context;
use std::task::Poll;
use tokio::io::AsyncRead;
pub struct HttpDecodeRead<R: AsyncRead + Unpin> {
framed_read: HttpFramedJoinContinuationRead<R>,
decoder: hpack::Decoder,
}
pub enum HttpFrameDecodedOrGoaway {
Frame(HttpFrameDecoded),
SendGoaway(ErrorCode),
_SendRst(StreamId, ErrorCode),
}
impl<R: AsyncRead + Unpin> HttpDecodeRead<R> {
pub fn new(read: R) -> Self {
HttpDecodeRead {
framed_read: HttpFramedJoinContinuationRead::new(read),
decoder: hpack::Decoder::new(),
}
}
pub fn poll_http_frame(
&mut self,
cx: &mut Context<'_>,
max_frame_size: u32,
) -> Poll<result::Result<HttpFrameDecodedOrGoaway>> {
let frame = match self.framed_read.poll_http_frame(cx, max_frame_size)? {
Poll::Ready(frame) => frame,
Poll::Pending => return Poll::Pending,
};
Poll::Ready(Ok(HttpFrameDecodedOrGoaway::Frame(match frame {
HttpFrame::Data(frame) => HttpFrameDecoded::Data(frame),
HttpFrame::Headers(frame) => {
let headers = match self.decoder.decode(frame.header_fragment) {
Err(e) => {
warn!("failed to decode headers: {:?}", e);
return Poll::Ready(Ok(HttpFrameDecodedOrGoaway::SendGoaway(
ErrorCode::CompressionError,
)));
}
Ok(headers) => headers,
};
let headers = match headers
.into_iter()
.map(|h| Header::new_validate(h.0, h.1))
.collect::<Result<Vec<_>, _>>()
.and_then(Headers::from_vec_pseudo_first)
{
Ok(headers) => headers,
Err(e) => {
warn!(
"received incorrect headers in stream {}: {:?}",
frame.stream_id, e
);
return Poll::Ready(Ok(HttpFrameDecodedOrGoaway::SendGoaway(
ErrorCode::ProtocolError,
)));
}
};
HttpFrameDecoded::Headers(HeadersDecodedFrame {
flags: frame.flags,
stream_id: frame.stream_id,
headers,
stream_dep: frame.stream_dep,
padding_len: frame.padding_len,
})
}
HttpFrame::Priority(frame) => HttpFrameDecoded::Priority(frame),
HttpFrame::RstStream(frame) => HttpFrameDecoded::RstStream(frame),
HttpFrame::Settings(frame) => HttpFrameDecoded::Settings(frame),
HttpFrame::PushPromise(frame) => HttpFrameDecoded::PushPromise(frame),
HttpFrame::Ping(frame) => HttpFrameDecoded::Ping(frame),
HttpFrame::Goaway(frame) => HttpFrameDecoded::Goaway(frame),
HttpFrame::WindowUpdate(frame) => HttpFrameDecoded::WindowUpdate(frame),
HttpFrame::Continuation(_frame) => {
unreachable!("must be joined with HEADERS before that")
}
HttpFrame::Unknown(frame) => HttpFrameDecoded::Unknown(frame),
})))
}
}