use crate::codec::http_decode_read::HttpFrameDecodedOrGoaway;
use crate::common::conn::Conn;
use crate::common::conn_write::ConnWriteSideCustom;
use crate::common::init_where::InitWhere;
use crate::common::stream::DroppedData;
use crate::common::stream::HttpStreamCommon;
use crate::common::stream::HttpStreamData;
use crate::common::stream::InMessageStage;
use crate::common::stream_map::HttpStreamRef;
use crate::common::types::Types;
use crate::error;
use crate::result;
use crate::solicit::end_stream::EndStream;
use crate::solicit::frame::DataFrame;
use crate::solicit::frame::Frame;
use crate::solicit::frame::GoawayFrame;
use crate::solicit::frame::HeadersDecodedFrame;
use crate::solicit::frame::HttpFrameDecoded;
use crate::solicit::frame::HttpFrameType;
use crate::solicit::frame::HttpSetting;
use crate::solicit::frame::PingFrame;
use crate::solicit::frame::PriorityFrame;
use crate::solicit::frame::RstStreamFrame;
use crate::solicit::frame::SettingsFrame;
use crate::solicit::frame::WindowUpdateFrame;
use crate::solicit::stream_id::StreamId;
use crate::solicit::window_size::MAX_WINDOW_SIZE;
use crate::solicit::DEFAULT_SETTINGS;
use crate::solicit_misc::HttpFrameClassified;
use crate::solicit_misc::HttpFrameConn;
use crate::solicit_misc::HttpFrameStream;
use crate::ErrorCode;
use crate::Headers;
use futures::task::Context;
use std::task::Poll;
use tokio::io::AsyncRead;
use tokio::io::AsyncWrite;
pub(crate) trait ConnReadSideCustom {
type Types: Types;
fn process_headers(
&mut self,
stream_id: StreamId,
end_stream: EndStream,
headers: Headers,
) -> result::Result<Option<HttpStreamRef<Self::Types>>>;
}
impl<T, I> Conn<T, I>
where
T: Types,
Self: ConnReadSideCustom<Types = T>,
Self: ConnWriteSideCustom<Types = T>,
HttpStreamCommon<T>: HttpStreamData<Types = T>,
I: AsyncWrite + AsyncRead + Send + 'static,
{
pub fn poll_recv_http_frame(
&mut self,
cx: &mut Context<'_>,
) -> Poll<result::Result<HttpFrameDecodedOrGoaway>> {
let max_frame_size = self.our_settings_ack.max_frame_size;
self.framed_read.poll_http_frame(cx, max_frame_size)
}
fn process_data_frame(&mut self, frame: DataFrame) -> result::Result<Option<HttpStreamRef<T>>> {
let stream_id = frame.get_stream_id();
self.decrease_in_window(frame.payload_len())?;
let increment_conn =
if self.in_window_size.size() < (DEFAULT_SETTINGS.initial_window_size / 2) as i32 {
let increment = DEFAULT_SETTINGS.initial_window_size;
let old_in_window_size = self.in_window_size.size();
self.in_window_size.try_increase(increment)
.map_err(|()| error::Error::ConnInWindowOverflow(self.in_window_size.size(), increment))?;
let new_in_window_size = self.in_window_size.size();
debug!("requesting increase in window: {} -> {}", old_in_window_size, new_in_window_size);
Some(increment)
} else {
None
};
let mut error = None;
loop {
let mut stream = match self
.get_stream_maybe_send_error(frame.get_stream_id(), HttpFrameType::Data)?
{
Some(stream) => stream,
None => {
return Ok(None);
}
};
if let Some(in_rem_content_length) = stream.stream().in_rem_content_length {
if in_rem_content_length < frame.data.len() as u64 {
warn!("stream data underflow content-length");
error = Some(ErrorCode::ProtocolError);
break;
}
let in_rem_content_length = in_rem_content_length - frame.data.len() as u64;
stream.stream().in_rem_content_length = Some(in_rem_content_length);
}
assert_eq!(
InMessageStage::AfterInitialHeaders,
stream.stream().in_message_stage
);
let old_in_window_size = stream.stream().in_window_size.size();
stream
.stream()
.in_window_size
.try_decrease_to_non_negative(frame.payload_len() as i32)
.map_err(|()| error::Error::CodeError(ErrorCode::FlowControlError))?;
let new_in_window_size = stream.stream().in_window_size.size();
debug!(
"decrease stream {} window: {} -> {}",
stream.id(),
old_in_window_size,
new_in_window_size
);
let end_of_stream = frame.is_end_of_stream();
stream.stream().data_recvd(frame.data, end_of_stream);
break;
}
if let Some(increment_conn) = increment_conn {
let window_update = WindowUpdateFrame::for_connection(increment_conn);
self.send_frame_and_notify(window_update);
}
if let Some(error) = error {
self.send_rst_stream(stream_id, error)?;
return Ok(None);
}
Ok(Some(
self.streams
.get_mut(stream_id)
.expect("stream must be found"),
))
}
fn process_ping(&mut self, frame: PingFrame) -> result::Result<()> {
if frame.is_ack() {
if let Some(opaque_data) = self.ping_sent.take() {
if opaque_data == frame.opaque_data {
Ok(())
} else {
Err(error::Error::PingAckOpaqueDataMismatch(
opaque_data,
frame.opaque_data,
))
}
} else {
warn!("PING ACK without PING");
Ok(())
}
} else {
let ping = PingFrame::new_ack(frame.opaque_data());
self.send_frame_and_notify(ping);
Ok(())
}
}
fn process_goaway(&mut self, frame: GoawayFrame) -> result::Result<()> {
if let Some(..) = self.goaway_received {
return Err(error::Error::GoawayAfterGoaway);
}
let last_stream_id = frame.last_stream_id;
let raw_error_code = frame.error_code.0;
self.goaway_received = Some(frame);
for (stream_id, mut stream) in self.streams.remove_local_streams_with_id_gt(last_stream_id)
{
debug!("removed stream {} because of GOAWAY", stream_id);
stream.goaway_recvd(raw_error_code);
}
Ok(())
}
fn process_headers_frame(
&mut self,
frame: HeadersDecodedFrame,
) -> result::Result<Option<HttpStreamRef<T>>> {
let end_stream = if frame.is_end_of_stream() {
EndStream::Yes
} else {
EndStream::No
};
self.process_headers(frame.stream_id, end_stream, frame.headers)
}
fn process_priority_frame(
&mut self,
frame: PriorityFrame,
) -> result::Result<Option<HttpStreamRef<T>>> {
Ok(self.streams.get_mut(frame.get_stream_id()))
}
fn process_settings_ack(&mut self, frame: SettingsFrame) -> result::Result<()> {
assert!(frame.is_ack());
if let Some(settings) = self.our_settings_sent.take() {
self.our_settings_ack = settings;
Ok(())
} else {
Err(error::Error::SettingsAckWithoutSettingsSent)
}
}
fn process_settings_req(&mut self, frame: SettingsFrame) -> result::Result<()> {
assert!(!frame.is_ack());
for setting in frame.settings {
match setting {
HttpSetting::InitialWindowSize(new_size) => {
if new_size > MAX_WINDOW_SIZE {
self.send_flow_control_error()?;
return Ok(());
}
let old_size = self.peer_settings.initial_window_size;
let delta = (new_size as i32) - (old_size as i32);
if delta != 0 {
self.streams.add_out_window(delta);
}
}
HttpSetting::HeaderTableSize(_new_size) => {}
_ => {}
}
self.peer_settings.apply(setting);
}
self.send_ack_settings()?;
Ok(())
}
fn process_settings(&mut self, frame: SettingsFrame) -> result::Result<()> {
if frame.is_ack() {
self.process_settings_ack(frame)
} else {
self.process_settings_req(frame)
}
}
fn process_stream_window_update_frame(
&mut self,
frame: WindowUpdateFrame,
) -> result::Result<Option<HttpStreamRef<T>>> {
let mut stream =
match self.get_stream_maybe_send_error(frame.stream_id, HttpFrameType::WindowUpdate)? {
Some(s) => s,
None => {
debug!("WINDOW_UPDATE of unknown stream: {}", frame.get_stream_id());
return Ok(None);
}
};
if let Err(..) = stream.try_increase_window_size(frame.increment) {
info!("failed to increment stream window: {}", frame.stream_id);
self.send_rst_stream(frame.stream_id, ErrorCode::FlowControlError)?;
return Ok(None);
}
let mut stream = self.streams.get_mut(frame.stream_id).unwrap();
stream
.stream()
.pump_out_window
.increase(frame.increment as isize);
Ok(Some(stream))
}
fn process_conn_window_update(&mut self, frame: WindowUpdateFrame) -> result::Result<()> {
assert_eq!(0, frame.stream_id);
let old_window_size = self.out_window_size.size();
if let Err(_) = self.out_window_size.try_increase(frame.increment) {
info!("attempted to increase window size too far");
self.send_flow_control_error()?;
return Ok(());
}
debug!(
"conn out window size change: {} -> {}",
old_window_size, self.out_window_size
);
self.pump_out_window_size.increase(frame.increment as usize);
Ok(())
}
fn process_rst_stream_frame(
&mut self,
frame: RstStreamFrame,
) -> result::Result<Option<HttpStreamRef<T>>> {
let stream_id = frame.get_stream_id();
let dropped_data = if let Some(stream) =
self.get_stream_maybe_send_error(stream_id, HttpFrameType::RstStream)?
{
stream.rst_received_remove(frame.error_code())
} else {
DroppedData { size: 0 }
};
{
let DroppedData { size } = dropped_data;
self.pump_out_window_size.increase(size);
}
self.peer_closed_streams.add(stream_id);
Ok(None)
}
fn process_conn_frame(&mut self, frame: HttpFrameConn) -> result::Result<()> {
match frame {
HttpFrameConn::Settings(f) => self.process_settings(f),
HttpFrameConn::Ping(f) => self.process_ping(f),
HttpFrameConn::Goaway(f) => self.process_goaway(f),
HttpFrameConn::WindowUpdate(f) => self.process_conn_window_update(f),
}
}
fn process_stream_frame(&mut self, frame: HttpFrameStream) -> result::Result<()> {
let stream_id = frame.get_stream_id();
let end_of_stream = frame.is_end_of_stream();
if let Some(ref f) = self.goaway_sent.as_ref() {
if T::init_where(stream_id) != InitWhere::Locally {
if stream_id > f.last_stream_id {
return Ok(());
}
}
}
{
let stream = match frame {
HttpFrameStream::Data(data) => self.process_data_frame(data)?,
HttpFrameStream::Headers(headers) => self.process_headers_frame(headers)?,
HttpFrameStream::Priority(priority) => self.process_priority_frame(priority)?,
HttpFrameStream::RstStream(rst) => self.process_rst_stream_frame(rst)?,
HttpFrameStream::PushPromise(_f) => {
return Err(error::Error::NotImplemented("PUSH_PROMISE"))
}
HttpFrameStream::WindowUpdate(window_update) => {
self.process_stream_window_update_frame(window_update)?
}
};
if let Some(stream) = stream {
if end_of_stream {
stream.close_remote();
}
}
}
if end_of_stream {
self.peer_closed_streams.add(stream_id);
}
Ok(())
}
fn process_http_frame(&mut self, frame: HttpFrameDecoded) -> result::Result<()> {
debug!("received frame: {:?}", frame);
match HttpFrameClassified::from(frame) {
HttpFrameClassified::Conn(f) => self.process_conn_frame(f),
HttpFrameClassified::Stream(f) => self.process_stream_frame(f),
HttpFrameClassified::Unknown(_f) => {
Ok(())
}
}
}
fn process_stream_error(
&mut self,
stream_id: StreamId,
error_code: ErrorCode,
) -> result::Result<()> {
if let Some(mut stream) = self.streams.get_mut(stream_id) {
stream.close_outgoing(error_code);
} else {
self.queued_write
.queue_not_goaway(RstStreamFrame::new(stream_id, error_code));
}
Ok(())
}
pub fn process_http_frame_of_goaway(
&mut self,
m: HttpFrameDecodedOrGoaway,
) -> result::Result<()> {
match m {
HttpFrameDecodedOrGoaway::Frame(frame) => self.process_http_frame(frame),
HttpFrameDecodedOrGoaway::_SendRst(stream_id, error_code) => {
self.process_stream_error(stream_id, error_code)
}
HttpFrameDecodedOrGoaway::SendGoaway(error_code) => self.send_goaway(error_code),
}
}
}