diff --git a/actix-web/CHANGES.md b/actix-web/CHANGES.md index 36e8b62dd..d1927cc65 100644 --- a/actix-web/CHANGES.md +++ b/actix-web/CHANGES.md @@ -23,6 +23,7 @@ - Always remove port from return value of `ConnectionInfo::realip_remote_addr()` when handling IPv6 addresses. from the `Forwarded` header. - The `UrlencodedError::ContentType` variant (relevant to the `Form` extractor) now uses the 415 (Media Type Unsupported) status code in it's `ResponseError` implementation. - Apply `HttpServer::max_connection_rate()` setting when using rustls v0.22 or v0.23. +- Always consume complete HTTP message body, even on error ## 4.7.0 diff --git a/actix-web/src/types/payload.rs b/actix-web/src/types/payload.rs index e4db37d0b..783dbd055 100644 --- a/actix-web/src/types/payload.rs +++ b/actix-web/src/types/payload.rs @@ -417,24 +417,23 @@ impl Future for HttpMessageBody { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.get_mut(); - if let Some(err) = this.err.take() { - return Poll::Ready(Err(err)); - } + while let Some(chunk) = ready!(Pin::new(&mut this.stream).poll_next(cx)) { + if this.err.is_some() { + continue; + } - loop { - let res = ready!(Pin::new(&mut this.stream).poll_next(cx)); - match res { - Some(chunk) => { - let chunk = chunk?; - if this.buf.len() + chunk.len() > this.limit { - return Poll::Ready(Err(PayloadError::Overflow)); - } else { - this.buf.extend_from_slice(&chunk); - } - } - None => return Poll::Ready(Ok(this.buf.split().freeze())), + let chunk = chunk?; + if this.buf.len() + chunk.len() > this.limit { + this.err = Some(PayloadError::Overflow); + } else { + this.buf.extend_from_slice(&chunk); } } + + Poll::Ready(match this.err.take() { + None => Ok(this.buf.split().freeze()), + Some(err) => Err(err), + }) } }