1
0
mirror of https://github.com/fafhrd91/actix-web synced 2024-11-30 18:44:35 +01:00

fix back pressure for h1 import stream

This commit is contained in:
Nikolay Kim 2018-02-09 16:20:10 -08:00
parent 728377a447
commit 74377ef73d
3 changed files with 71 additions and 52 deletions

View File

@ -260,6 +260,7 @@ impl PayloadWriter for PayloadSender {
} }
} }
#[inline]
fn capacity(&self) -> usize { fn capacity(&self) -> usize {
if let Some(shared) = self.inner.upgrade() { if let Some(shared) = self.inner.upgrade() {
shared.borrow().capacity() shared.borrow().capacity()
@ -327,10 +328,10 @@ impl Inner {
if let Some(data) = self.items.pop_front() { if let Some(data) = self.items.pop_front() {
self.len -= data.len(); self.len -= data.len();
Ok(Async::Ready(Some(PayloadItem(data)))) Ok(Async::Ready(Some(PayloadItem(data))))
} else if self.eof {
Ok(Async::Ready(None))
} else if let Some(err) = self.err.take() { } else if let Some(err) = self.err.take() {
Err(err) Err(err)
} else if self.eof {
Ok(Async::Ready(None))
} else { } else {
self.task = Some(current_task()); self.task = Some(current_task());
Ok(Async::NotReady) Ok(Async::NotReady)
@ -439,6 +440,7 @@ impl Inner {
self.items.push_front(data); self.items.push_front(data);
} }
#[inline]
fn capacity(&self) -> usize { fn capacity(&self) -> usize {
if self.len > self.buf_size { if self.len > self.buf_size {
0 0

View File

@ -94,6 +94,7 @@ impl PayloadType {
} }
impl PayloadWriter for PayloadType { impl PayloadWriter for PayloadType {
#[inline]
fn set_error(&mut self, err: PayloadError) { fn set_error(&mut self, err: PayloadError) {
match *self { match *self {
PayloadType::Sender(ref mut sender) => sender.set_error(err), PayloadType::Sender(ref mut sender) => sender.set_error(err),
@ -101,6 +102,7 @@ impl PayloadWriter for PayloadType {
} }
} }
#[inline]
fn feed_eof(&mut self) { fn feed_eof(&mut self) {
match *self { match *self {
PayloadType::Sender(ref mut sender) => sender.feed_eof(), PayloadType::Sender(ref mut sender) => sender.feed_eof(),
@ -108,6 +110,7 @@ impl PayloadWriter for PayloadType {
} }
} }
#[inline]
fn feed_data(&mut self, data: Bytes) { fn feed_data(&mut self, data: Bytes) {
match *self { match *self {
PayloadType::Sender(ref mut sender) => sender.feed_data(data), PayloadType::Sender(ref mut sender) => sender.feed_data(data),
@ -115,6 +118,7 @@ impl PayloadWriter for PayloadType {
} }
} }
#[inline]
fn capacity(&self) -> usize { fn capacity(&self) -> usize {
match *self { match *self {
PayloadType::Sender(ref sender) => sender.capacity(), PayloadType::Sender(ref sender) => sender.capacity(),

View File

@ -16,7 +16,7 @@ use pipeline::Pipeline;
use httpcodes::HTTPNotFound; use httpcodes::HTTPNotFound;
use httprequest::HttpRequest; use httprequest::HttpRequest;
use error::{ParseError, PayloadError, ResponseError}; use error::{ParseError, PayloadError, ResponseError};
use payload::{Payload, PayloadWriter, DEFAULT_BUFFER_SIZE}; use payload::{Payload, PayloadWriter};
use super::{utils, Writer}; use super::{utils, Writer};
use super::h1writer::H1Writer; use super::h1writer::H1Writer;
@ -319,7 +319,6 @@ struct Reader {
} }
enum Decoding { enum Decoding {
Paused,
Ready, Ready,
NotReady, NotReady,
} }
@ -343,11 +342,10 @@ impl Reader {
} }
} }
fn decode(&mut self, buf: &mut BytesMut) -> std::result::Result<Decoding, ReaderError> { #[inline]
if let Some(ref mut payload) = self.payload { fn decode(&mut self, buf: &mut BytesMut, payload: &mut PayloadInfo)
if payload.tx.capacity() > DEFAULT_BUFFER_SIZE { -> std::result::Result<Decoding, ReaderError>
return Ok(Decoding::Paused) {
}
loop { loop {
match payload.decoder.decode(buf) { match payload.decoder.decode(buf) {
Ok(Async::Ready(Some(bytes))) => { Ok(Async::Ready(Some(bytes))) => {
@ -364,9 +362,6 @@ impl Reader {
} }
} }
} }
} else {
return Ok(Decoding::Ready)
}
} }
pub fn parse<T, H>(&mut self, io: &mut T, pub fn parse<T, H>(&mut self, io: &mut T,
@ -375,29 +370,48 @@ impl Reader {
where T: IoStream where T: IoStream
{ {
// read payload // read payload
if self.payload.is_some() { let done = {
if let Some(ref mut payload) = self.payload {
if payload.tx.capacity() == 0 {
return Ok(Async::NotReady)
}
match utils::read_from_io(io, buf) { match utils::read_from_io(io, buf) {
Ok(Async::Ready(0)) => { Ok(Async::Ready(0)) => {
if let Some(ref mut payload) = self.payload {
payload.tx.set_error(PayloadError::Incomplete); payload.tx.set_error(PayloadError::Incomplete);
}
// http channel should not deal with payload errors // http channel should not deal with payload errors
return Err(ReaderError::Payload) return Err(ReaderError::Payload)
}, },
Err(err) => { Err(err) => {
if let Some(ref mut payload) = self.payload {
payload.tx.set_error(err.into()); payload.tx.set_error(err.into());
}
// http channel should not deal with payload errors // http channel should not deal with payload errors
return Err(ReaderError::Payload) return Err(ReaderError::Payload)
} }
_ => (), _ => (),
} }
match self.decode(buf)? { loop {
Decoding::Ready => self.payload = None, match payload.decoder.decode(buf) {
Decoding::Paused | Decoding::NotReady => return Ok(Async::NotReady), Ok(Async::Ready(Some(bytes))) => {
payload.tx.feed_data(bytes)
},
Ok(Async::Ready(None)) => {
payload.tx.feed_eof();
break true
},
Ok(Async::NotReady) =>
break false,
Err(err) => {
payload.tx.set_error(err.into());
return Err(ReaderError::Payload)
} }
} }
}
} else {
false
}
};
if done { self.payload = None }
// if buf is empty parse_message will always return NotReady, let's avoid that // if buf is empty parse_message will always return NotReady, let's avoid that
let read = if buf.is_empty() { let read = if buf.is_empty() {
@ -421,11 +435,10 @@ impl Reader {
match Reader::parse_message(buf, settings).map_err(ReaderError::Error)? { match Reader::parse_message(buf, settings).map_err(ReaderError::Error)? {
Async::Ready((msg, decoder)) => { Async::Ready((msg, decoder)) => {
// process payload // process payload
if let Some(payload) = decoder { if let Some(mut payload) = decoder {
self.payload = Some(payload); match self.decode(buf, &mut payload)? {
match self.decode(buf)? { Decoding::Ready => (),
Decoding::Paused | Decoding::NotReady => (), Decoding::NotReady => self.payload = Some(payload),
Decoding::Ready => self.payload = None,
} }
} }
return Ok(Async::Ready(msg)); return Ok(Async::Ready(msg));