fix(http): send errors as frame errors
Additionally, only close read side, so it's potentially possible to write a response for an error.
This commit is contained in:
@@ -83,25 +83,20 @@ impl<I: Io, T: Http1Transaction, K: KeepAlive> Conn<I, T, K> {
|
|||||||
Ok(Some(head)) => (head.version, head),
|
Ok(Some(head)) => (head.version, head),
|
||||||
Ok(None) => return Ok(Async::NotReady),
|
Ok(None) => return Ok(Async::NotReady),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let must_respond_with_error = !self.state.was_idle();
|
self.state.close_read();
|
||||||
self.state.close();
|
|
||||||
self.io.consume_leading_lines();
|
self.io.consume_leading_lines();
|
||||||
let ret = if !self.io.read_buf().is_empty() {
|
let was_mid_parse = !self.io.read_buf().is_empty();
|
||||||
error!("parse error ({}) with bytes: {:?}", e, self.io.read_buf());
|
let must_respond_with_error = !self.state.was_idle();
|
||||||
|
return if was_mid_parse {
|
||||||
|
debug!("parse error ({}) with bytes: {:?}", e, self.io.read_buf());
|
||||||
|
Ok(Async::Ready(Some(Frame::Error { error: e })))
|
||||||
|
} else if must_respond_with_error {
|
||||||
|
trace!("parse error with 0 input, err = {:?}", e);
|
||||||
Ok(Async::Ready(Some(Frame::Error { error: e })))
|
Ok(Async::Ready(Some(Frame::Error { error: e })))
|
||||||
} else {
|
} else {
|
||||||
trace!("parse error with 0 input, err = {:?}", e);
|
debug!("socket complete");
|
||||||
if must_respond_with_error {
|
Ok(Async::Ready(None))
|
||||||
match e {
|
|
||||||
::Error::Io(io) => Err(io),
|
|
||||||
other => Err(io::Error::new(io::ErrorKind::UnexpectedEof, other)),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
debug!("socket complete");
|
|
||||||
Ok(Async::Ready(None))
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -111,7 +106,7 @@ impl<I: Io, T: Http1Transaction, K: KeepAlive> Conn<I, T, K> {
|
|||||||
Ok(d) => d,
|
Ok(d) => d,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("decoder error = {:?}", e);
|
error!("decoder error = {:?}", e);
|
||||||
self.state.close();
|
self.state.close_read();
|
||||||
return Ok(Async::Ready(Some(Frame::Error { error: e })));
|
return Ok(Async::Ready(Some(Frame::Error { error: e })));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -128,7 +123,7 @@ impl<I: Io, T: Http1Transaction, K: KeepAlive> Conn<I, T, K> {
|
|||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
error!("unimplemented HTTP Version = {:?}", version);
|
error!("unimplemented HTTP Version = {:?}", version);
|
||||||
self.state.close();
|
self.state.close_read();
|
||||||
return Ok(Async::Ready(Some(Frame::Error { error: ::Error::Version })));
|
return Ok(Async::Ready(Some(Frame::Error { error: ::Error::Version })));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -310,6 +305,10 @@ where I: Io,
|
|||||||
.map(|async| async.map(|chunk| Some(Frame::Body {
|
.map(|async| async.map(|chunk| Some(Frame::Body {
|
||||||
chunk: chunk
|
chunk: chunk
|
||||||
})))
|
})))
|
||||||
|
.or_else(|err| {
|
||||||
|
self.state.close_read();
|
||||||
|
Ok(Async::Ready(Some(Frame::Error { error: err.into() })))
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
trace!("poll when on keep-alive");
|
trace!("poll when on keep-alive");
|
||||||
Ok(Async::NotReady)
|
Ok(Async::NotReady)
|
||||||
@@ -476,6 +475,12 @@ impl<K: KeepAlive> State<K> {
|
|||||||
self.keep_alive.disable();
|
self.keep_alive.disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn close_read(&mut self) {
|
||||||
|
trace!("State::close_read()");
|
||||||
|
self.reading = Reading::Closed;
|
||||||
|
self.keep_alive.disable();
|
||||||
|
}
|
||||||
|
|
||||||
fn try_keep_alive(&mut self) {
|
fn try_keep_alive(&mut self) {
|
||||||
match (&self.reading, &self.writing) {
|
match (&self.reading, &self.writing) {
|
||||||
(&Reading::KeepAlive, &Writing::KeepAlive) => {
|
(&Reading::KeepAlive, &Writing::KeepAlive) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user