Skip to content

Commit

Permalink
simplify AnyBody and BodySize (actix#2446)
Browse files Browse the repository at this point in the history
  • Loading branch information
robjtede authored Nov 16, 2021
1 parent e8a0e16 commit 4df1cd7
Show file tree
Hide file tree
Showing 17 changed files with 67 additions and 65 deletions.
11 changes: 11 additions & 0 deletions actix-http/CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
# Changes

## Unreleased - 2021-xx-xx
### Added
* `AnyBody::empty` for quickly creating an empty body. [#2446]

### Changed
* Rename `AnyBody::{Message => Stream}`. [#2446]

### Removed
* `AnyBody::Empty`; an empty body can now only be represented as a zero-length `Bytes` variant. [#2446]
* `BodySize::Empty`; an empty body can now only be represented as a `Sized(0)` variant. [#2446]

[#2446]: https://github.com/actix/actix-web/pull/2446


## 3.0.0-beta.12 - 2021-11-15
Expand Down
24 changes: 11 additions & 13 deletions actix-http/src/body/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,19 @@ pub enum AnyBody {
/// Empty response. `Content-Length` header is not set.
None,

/// Zero sized response body. `Content-Length` header is set to `0`.
Empty,

/// Specific response body.
Bytes(Bytes),

/// Generic message body.
Message(BoxAnyBody),
Stream(BoxAnyBody),
}

impl AnyBody {
/// Constructs a new, empty body.
pub fn empty() -> Self {
Self::Bytes(Bytes::new())
}

/// Create body from slice (copy)
pub fn from_slice(s: &[u8]) -> Self {
Self::Bytes(Bytes::copy_from_slice(s))
Expand All @@ -42,7 +44,7 @@ impl AnyBody {
B: MessageBody + 'static,
B::Error: Into<Box<dyn StdError + 'static>>,
{
Self::Message(BoxAnyBody::from_body(body))
Self::Stream(BoxAnyBody::from_body(body))
}
}

Expand All @@ -52,9 +54,8 @@ impl MessageBody for AnyBody {
fn size(&self) -> BodySize {
match self {
AnyBody::None => BodySize::None,
AnyBody::Empty => BodySize::Empty,
AnyBody::Bytes(ref bin) => BodySize::Sized(bin.len() as u64),
AnyBody::Message(ref body) => body.size(),
AnyBody::Stream(ref body) => body.size(),
}
}

Expand All @@ -64,7 +65,6 @@ impl MessageBody for AnyBody {
) -> Poll<Option<Result<Bytes, Self::Error>>> {
match self.get_mut() {
AnyBody::None => Poll::Ready(None),
AnyBody::Empty => Poll::Ready(None),
AnyBody::Bytes(ref mut bin) => {
let len = bin.len();
if len == 0 {
Expand All @@ -74,7 +74,7 @@ impl MessageBody for AnyBody {
}
}

AnyBody::Message(body) => body
AnyBody::Stream(body) => body
.as_pin_mut()
.poll_next(cx)
.map_err(|err| Error::new_body().with_cause(err)),
Expand All @@ -86,12 +86,11 @@ impl PartialEq for AnyBody {
fn eq(&self, other: &Body) -> bool {
match *self {
AnyBody::None => matches!(*other, AnyBody::None),
AnyBody::Empty => matches!(*other, AnyBody::Empty),
AnyBody::Bytes(ref b) => match *other {
AnyBody::Bytes(ref b2) => b == b2,
_ => false,
},
AnyBody::Message(_) => false,
AnyBody::Stream(_) => false,
}
}
}
Expand All @@ -100,9 +99,8 @@ impl fmt::Debug for AnyBody {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
AnyBody::None => write!(f, "AnyBody::None"),
AnyBody::Empty => write!(f, "AnyBody::Empty"),
AnyBody::Bytes(ref b) => write!(f, "AnyBody::Bytes({:?})", b),
AnyBody::Message(_) => write!(f, "AnyBody::Message(_)"),
AnyBody::Stream(_) => write!(f, "AnyBody::Message(_)"),
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion actix-http/src/body/message_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl MessageBody for () {
type Error = Infallible;

fn size(&self) -> BodySize {
BodySize::Empty
BodySize::Sized(0)
}

fn poll_next(
Expand Down
14 changes: 7 additions & 7 deletions actix-http/src/body/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub use self::sized_stream::SizedStream;
/// use bytes::Bytes;
///
/// # async fn test_to_bytes() {
/// let body = Body::Empty;
/// let body = Body::None;
/// let bytes = to_bytes(body).await.unwrap();
/// assert!(bytes.is_empty());
///
Expand All @@ -44,8 +44,9 @@ pub use self::sized_stream::SizedStream;
/// ```
pub async fn to_bytes<B: MessageBody>(body: B) -> Result<Bytes, B::Error> {
let cap = match body.size() {
BodySize::None | BodySize::Empty | BodySize::Sized(0) => return Ok(Bytes::new()),
BodySize::None | BodySize::Sized(0) => return Ok(Bytes::new()),
BodySize::Sized(size) => size as usize,
// good enough first guess for chunk size
BodySize::Stream => 32_768,
};

Expand Down Expand Up @@ -184,7 +185,7 @@ mod tests {

#[actix_rt::test]
async fn test_unit() {
assert_eq!(().size(), BodySize::Empty);
assert_eq!(().size(), BodySize::Sized(0));
assert!(poll_fn(|cx| Pin::new(&mut ()).poll_next(cx))
.await
.is_none());
Expand All @@ -194,11 +195,11 @@ mod tests {
async fn test_box_and_pin() {
let val = Box::new(());
pin!(val);
assert_eq!(val.size(), BodySize::Empty);
assert_eq!(val.size(), BodySize::Sized(0));
assert!(poll_fn(|cx| val.as_mut().poll_next(cx)).await.is_none());

let mut val = Box::pin(());
assert_eq!(val.size(), BodySize::Empty);
assert_eq!(val.size(), BodySize::Sized(0));
assert!(poll_fn(|cx| val.as_mut().poll_next(cx)).await.is_none());
}

Expand All @@ -214,7 +215,6 @@ mod tests {
#[actix_rt::test]
async fn test_body_debug() {
assert!(format!("{:?}", Body::None).contains("Body::None"));
assert!(format!("{:?}", Body::Empty).contains("Body::Empty"));
assert!(format!("{:?}", Body::Bytes(Bytes::from_static(b"1"))).contains('1'));
}

Expand Down Expand Up @@ -252,7 +252,7 @@ mod tests {

#[actix_rt::test]
async fn test_to_bytes() {
let body = Body::Empty;
let body = Body::empty();
let bytes = to_bytes(body).await.unwrap();
assert!(bytes.is_empty());

Expand Down
12 changes: 4 additions & 8 deletions actix-http/src/body/size.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,9 @@ pub enum BodySize {
/// Will skip writing Content-Length header.
None,

/// Zero size body.
///
/// Will write `Content-Length: 0` header.
Empty,

/// Known size body.
///
/// Will write `Content-Length: N` header. `Sized(0)` is treated the same as `Empty`.
/// Will write `Content-Length: N` header.
Sized(u64),

/// Unknown size body.
Expand All @@ -25,16 +20,17 @@ pub enum BodySize {
impl BodySize {
/// Returns true if size hint indicates no or empty body.
///
/// Streams will return false because it cannot be known without reading the stream.
///
/// ```
/// # use actix_http::body::BodySize;
/// assert!(BodySize::None.is_eof());
/// assert!(BodySize::Empty.is_eof());
/// assert!(BodySize::Sized(0).is_eof());
///
/// assert!(!BodySize::Sized(64).is_eof());
/// assert!(!BodySize::Stream.is_eof());
/// ```
pub fn is_eof(&self) -> bool {
matches!(self, BodySize::None | BodySize::Empty | BodySize::Sized(0))
matches!(self, BodySize::None | BodySize::Sized(0))
}
}
3 changes: 1 addition & 2 deletions actix-http/src/encoding/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,14 @@ impl<B: MessageBody> Encoder<B> {
let body = match body {
ResponseBody::Other(b) => match b {
Body::None => return ResponseBody::Other(Body::None),
Body::Empty => return ResponseBody::Other(Body::Empty),
Body::Bytes(buf) => {
if can_encode {
EncoderBody::Bytes(buf)
} else {
return ResponseBody::Other(Body::Bytes(buf));
}
}
Body::Message(stream) => EncoderBody::BoxedStream(stream),
Body::Stream(stream) => EncoderBody::BoxedStream(stream),
},
ResponseBody::Body(stream) => EncoderBody::Stream(stream),
};
Expand Down
8 changes: 4 additions & 4 deletions actix-http/src/h1/dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ where
) -> Result<(), DispatchError> {
let size = self.as_mut().send_response_inner(message, &body)?;
let state = match size {
BodySize::None | BodySize::Empty => State::None,
BodySize::None | BodySize::Sized(0) => State::None,
_ => State::SendPayload(body),
};
self.project().state.set(state);
Expand All @@ -339,7 +339,7 @@ where
) -> Result<(), DispatchError> {
let size = self.as_mut().send_response_inner(message, &body)?;
let state = match size {
BodySize::None | BodySize::Empty => State::None,
BodySize::None | BodySize::Sized(0) => State::None,
_ => State::SendErrorPayload(body),
};
self.project().state.set(state);
Expand Down Expand Up @@ -380,7 +380,7 @@ where
// send_response would update InnerDispatcher state to SendPayload or
// None(If response body is empty).
// continue loop to poll it.
self.as_mut().send_error_response(res, AnyBody::Empty)?;
self.as_mut().send_error_response(res, AnyBody::empty())?;
}

// return with upgrade request and poll it exclusively.
Expand Down Expand Up @@ -772,7 +772,7 @@ where
trace!("Slow request timeout");
let _ = self.as_mut().send_error_response(
Response::with_body(StatusCode::REQUEST_TIMEOUT, ()),
AnyBody::Empty,
AnyBody::empty(),
);
this = self.project();
this.flags.insert(Flags::STARTED | Flags::SHUTDOWN);
Expand Down
15 changes: 6 additions & 9 deletions actix-http/src/h1/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,10 @@ pub(crate) trait MessageType: Sized {
dst.put_slice(b"\r\n");
}
}
BodySize::Empty => {
if camel_case {
dst.put_slice(b"\r\nContent-Length: 0\r\n");
} else {
dst.put_slice(b"\r\ncontent-length: 0\r\n");
}
BodySize::Sized(0) if camel_case => {
dst.put_slice(b"\r\nContent-Length: 0\r\n")
}
BodySize::Sized(0) => dst.put_slice(b"\r\ncontent-length: 0\r\n"),
BodySize::Sized(len) => helpers::write_content_length(len, dst),
BodySize::None => dst.put_slice(b"\r\n"),
}
Expand Down Expand Up @@ -336,7 +333,7 @@ impl<T: MessageType> MessageEncoder<T> {
// transfer encoding
if !head {
self.te = match length {
BodySize::Empty => TransferEncoding::empty(),
BodySize::Sized(0) => TransferEncoding::empty(),
BodySize::Sized(len) => TransferEncoding::length(len),
BodySize::Stream => {
if message.chunked() && !stream {
Expand Down Expand Up @@ -553,7 +550,7 @@ mod tests {
let _ = head.encode_headers(
&mut bytes,
Version::HTTP_11,
BodySize::Empty,
BodySize::Sized(0),
ConnectionType::Close,
&ServiceConfig::default(),
);
Expand Down Expand Up @@ -624,7 +621,7 @@ mod tests {
let _ = head.encode_headers(
&mut bytes,
Version::HTTP_11,
BodySize::Empty,
BodySize::Sized(0),
ConnectionType::Close,
&ServiceConfig::default(),
);
Expand Down
4 changes: 3 additions & 1 deletion actix-http/src/h2/dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,11 @@ fn prepare_response(

let _ = match size {
BodySize::None | BodySize::Stream => None,
BodySize::Empty => res

BodySize::Sized(0) => res
.headers_mut()
.insert(CONTENT_LENGTH, HeaderValue::from_static("0")),

BodySize::Sized(len) => {
let mut buf = itoa::Buffer::new();

Expand Down
2 changes: 1 addition & 1 deletion actix-http/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl Response<AnyBody> {
pub fn new(status: StatusCode) -> Self {
Response {
head: BoxedResponseHead::new(status),
body: AnyBody::Empty,
body: AnyBody::empty(),
}
}

Expand Down
4 changes: 2 additions & 2 deletions actix-http/src/response_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ impl ResponseBuilder {
/// This `ResponseBuilder` will be left in a useless state.
#[inline]
pub fn finish(&mut self) -> Response<AnyBody> {
self.body(AnyBody::Empty)
self.body(AnyBody::empty())
}

/// Create an owned `ResponseBuilder`, leaving the original in a useless state.
Expand Down Expand Up @@ -390,7 +390,7 @@ mod tests {
fn test_content_type() {
let resp = Response::build(StatusCode::OK)
.content_type("text/plain")
.body(Body::Empty);
.body(Body::empty());
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "text/plain")
}

Expand Down
4 changes: 2 additions & 2 deletions awc/src/client/h1proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ where
// RFC: https://tools.ietf.org/html/rfc7231#section-5.1.1
let is_expect = if head.as_ref().headers.contains_key(EXPECT) {
match body.size() {
BodySize::None | BodySize::Empty | BodySize::Sized(0) => {
BodySize::None | BodySize::Sized(0) => {
let keep_alive = framed.codec_ref().keepalive();
framed.io_mut().on_release(keep_alive);

Expand Down Expand Up @@ -104,7 +104,7 @@ where
if do_send {
// send request body
match body.size() {
BodySize::None | BodySize::Empty | BodySize::Sized(0) => {}
BodySize::None | BodySize::Sized(0) => {}
_ => send_body(body, pin_framed.as_mut()).await?,
};

Expand Down
Loading

0 comments on commit 4df1cd7

Please sign in to comment.