1
0
mirror of https://github.com/fafhrd91/actix-web synced 2024-11-28 01:52:57 +01:00

re-introduce Body type, use Body as default body type for Response

This commit is contained in:
Nikolay Kim 2018-11-18 13:48:42 -08:00
parent 7fed50bcae
commit 8fea1367c7
16 changed files with 309 additions and 335 deletions

View File

@ -1,22 +1,19 @@
use std::mem;
use std::sync::Arc;
use std::marker::PhantomData;
use std::{fmt, mem};
use bytes::{Bytes, BytesMut};
use futures::{Async, Poll, Stream};
use error::{Error, PayloadError};
/// Type represent streaming body
pub type BodyStream = Box<dyn Stream<Item = Bytes, Error = Error>>;
/// Type represent streaming payload
pub type PayloadStream = Box<dyn Stream<Item = Bytes, Error = PayloadError>>;
#[derive(Debug)]
#[derive(Debug, PartialEq)]
/// Different type of body
pub enum BodyLength {
None,
Zero,
Empty,
Sized(usize),
Sized64(u64),
Chunked,
@ -32,7 +29,7 @@ pub trait MessageBody {
impl MessageBody for () {
fn length(&self) -> BodyLength {
BodyLength::Zero
BodyLength::Empty
}
fn poll_next(&mut self) -> Poll<Option<Bytes>, Error> {
@ -40,150 +37,129 @@ impl MessageBody for () {
}
}
/// Represents various types of binary body.
/// `Content-Length` header is set to length of the body.
#[derive(Debug, PartialEq)]
pub enum Binary {
/// Bytes body
/// Represents various types of http message body.
pub enum Body {
/// 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),
/// Static slice
Slice(&'static [u8]),
/// Shared string body
#[doc(hidden)]
SharedString(Arc<String>),
/// Shared vec body
SharedVec(Arc<Vec<u8>>),
/// Generic message body.
Message(Box<dyn MessageBody>),
}
impl Binary {
#[inline]
/// Returns `true` if body is empty
pub fn is_empty(&self) -> bool {
self.len() == 0
impl Body {
/// Create body from slice (copy)
pub fn from_slice(s: &[u8]) -> Body {
Body::Bytes(Bytes::from(s))
}
#[inline]
/// Length of body in bytes
pub fn len(&self) -> usize {
match *self {
Binary::Bytes(ref bytes) => bytes.len(),
Binary::Slice(slice) => slice.len(),
Binary::SharedString(ref s) => s.len(),
Binary::SharedVec(ref s) => s.len(),
}
}
/// Create binary body from slice
pub fn from_slice(s: &[u8]) -> Binary {
Binary::Bytes(Bytes::from(s))
}
/// Convert Binary to a Bytes instance
pub fn take(&mut self) -> Bytes {
mem::replace(self, Binary::Slice(b"")).into()
/// Create body from generic message body.
pub fn from_message<B: MessageBody + 'static>(body: B) -> Body {
Body::Message(Box::new(body))
}
}
impl Clone for Binary {
fn clone(&self) -> Binary {
match *self {
Binary::Bytes(ref bytes) => Binary::Bytes(bytes.clone()),
Binary::Slice(slice) => Binary::Bytes(Bytes::from(slice)),
Binary::SharedString(ref s) => Binary::SharedString(s.clone()),
Binary::SharedVec(ref s) => Binary::SharedVec(s.clone()),
}
}
}
impl Into<Bytes> for Binary {
fn into(self) -> Bytes {
impl MessageBody for Body {
fn length(&self) -> BodyLength {
match self {
Binary::Bytes(bytes) => bytes,
Binary::Slice(slice) => Bytes::from(slice),
Binary::SharedString(s) => Bytes::from(s.as_str()),
Binary::SharedVec(s) => Bytes::from(AsRef::<[u8]>::as_ref(s.as_ref())),
Body::None => BodyLength::None,
Body::Empty => BodyLength::Empty,
Body::Bytes(ref bin) => BodyLength::Sized(bin.len()),
Body::Message(ref body) => body.length(),
}
}
fn poll_next(&mut self) -> Poll<Option<Bytes>, Error> {
match self {
Body::None => Ok(Async::Ready(None)),
Body::Empty => Ok(Async::Ready(None)),
Body::Bytes(ref mut bin) => {
if bin.len() == 0 {
Ok(Async::Ready(None))
} else {
Ok(Async::Ready(Some(bin.slice_to(bin.len()))))
}
}
Body::Message(ref mut body) => body.poll_next(),
}
}
}
impl From<&'static str> for Binary {
fn from(s: &'static str) -> Binary {
Binary::Slice(s.as_ref())
}
}
impl From<&'static [u8]> for Binary {
fn from(s: &'static [u8]) -> Binary {
Binary::Slice(s)
}
}
impl From<Vec<u8>> for Binary {
fn from(vec: Vec<u8>) -> Binary {
Binary::Bytes(Bytes::from(vec))
}
}
impl From<String> for Binary {
fn from(s: String) -> Binary {
Binary::Bytes(Bytes::from(s))
}
}
impl<'a> From<&'a String> for Binary {
fn from(s: &'a String) -> Binary {
Binary::Bytes(Bytes::from(AsRef::<[u8]>::as_ref(&s)))
}
}
impl From<Bytes> for Binary {
fn from(s: Bytes) -> Binary {
Binary::Bytes(s)
}
}
impl From<BytesMut> for Binary {
fn from(s: BytesMut) -> Binary {
Binary::Bytes(s.freeze())
}
}
impl From<Arc<String>> for Binary {
fn from(body: Arc<String>) -> Binary {
Binary::SharedString(body)
}
}
impl<'a> From<&'a Arc<String>> for Binary {
fn from(body: &'a Arc<String>) -> Binary {
Binary::SharedString(Arc::clone(body))
}
}
impl From<Arc<Vec<u8>>> for Binary {
fn from(body: Arc<Vec<u8>>) -> Binary {
Binary::SharedVec(body)
}
}
impl<'a> From<&'a Arc<Vec<u8>>> for Binary {
fn from(body: &'a Arc<Vec<u8>>) -> Binary {
Binary::SharedVec(Arc::clone(body))
}
}
impl AsRef<[u8]> for Binary {
#[inline]
fn as_ref(&self) -> &[u8] {
impl PartialEq for Body {
fn eq(&self, other: &Body) -> bool {
match *self {
Binary::Bytes(ref bytes) => bytes.as_ref(),
Binary::Slice(slice) => slice,
Binary::SharedString(ref s) => s.as_bytes(),
Binary::SharedVec(ref s) => s.as_ref().as_ref(),
Body::None => match *other {
Body::None => true,
_ => false,
},
Body::Empty => match *other {
Body::Empty => true,
_ => false,
},
Body::Bytes(ref b) => match *other {
Body::Bytes(ref b2) => b == b2,
_ => false,
},
Body::Message(_) => false,
}
}
}
impl fmt::Debug for Body {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Body::None => write!(f, "Body::None"),
Body::Empty => write!(f, "Body::Zero"),
Body::Bytes(ref b) => write!(f, "Body::Bytes({:?})", b),
Body::Message(_) => write!(f, "Body::Message(_)"),
}
}
}
impl From<&'static str> for Body {
fn from(s: &'static str) -> Body {
Body::Bytes(Bytes::from_static(s.as_ref()))
}
}
impl From<&'static [u8]> for Body {
fn from(s: &'static [u8]) -> Body {
Body::Bytes(Bytes::from_static(s.as_ref()))
}
}
impl From<Vec<u8>> for Body {
fn from(vec: Vec<u8>) -> Body {
Body::Bytes(Bytes::from(vec))
}
}
impl From<String> for Body {
fn from(s: String) -> Body {
s.into_bytes().into()
}
}
impl<'a> From<&'a String> for Body {
fn from(s: &'a String) -> Body {
Body::Bytes(Bytes::from(AsRef::<[u8]>::as_ref(&s)))
}
}
impl From<Bytes> for Body {
fn from(s: Bytes) -> Body {
Body::Bytes(s)
}
}
impl From<BytesMut> for Body {
fn from(s: BytesMut) -> Body {
Body::Bytes(s.freeze())
}
}
impl MessageBody for Bytes {
fn length(&self) -> BodyLength {
BodyLength::Sized(self.len())
@ -279,26 +255,62 @@ impl MessageBody for String {
}
}
#[doc(hidden)]
pub struct MessageBodyStream<S> {
/// Type represent streaming body.
/// Response does not contain `content-length` header and appropriate transfer encoding is used.
pub struct BodyStream<S, E> {
stream: S,
_t: PhantomData<E>,
}
impl<S> MessageBodyStream<S>
impl<S, E> BodyStream<S, E>
where
S: Stream<Item = Bytes, Error = Error>,
S: Stream<Item = Bytes, Error = E>,
E: Into<Error>,
{
pub fn new(stream: S) -> Self {
MessageBodyStream { stream }
BodyStream {
stream,
_t: PhantomData,
}
}
}
impl<S> MessageBody for MessageBodyStream<S>
impl<S, E> MessageBody for BodyStream<S, E>
where
S: Stream<Item = Bytes, Error = E>,
E: Into<Error>,
{
fn length(&self) -> BodyLength {
BodyLength::Chunked
}
fn poll_next(&mut self) -> Poll<Option<Bytes>, Error> {
self.stream.poll().map_err(|e| e.into())
}
}
/// Type represent streaming body. This body implementation should be used
/// if total size of stream is known. Data get sent as is without using transfer encoding.
pub struct SizedStream<S> {
size: usize,
stream: S,
}
impl<S> SizedStream<S>
where
S: Stream<Item = Bytes, Error = Error>,
{
pub fn new(size: usize, stream: S) -> Self {
SizedStream { size, stream }
}
}
impl<S> MessageBody for SizedStream<S>
where
S: Stream<Item = Bytes, Error = Error>,
{
fn length(&self) -> BodyLength {
BodyLength::Chunked
BodyLength::Sized(self.size)
}
fn poll_next(&mut self) -> Poll<Option<Bytes>, Error> {
@ -310,78 +322,61 @@ where
mod tests {
use super::*;
#[test]
fn test_is_empty() {
assert_eq!(Binary::from("").is_empty(), true);
assert_eq!(Binary::from("test").is_empty(), false);
impl Body {
pub(crate) fn get_ref(&self) -> &[u8] {
match *self {
Body::Bytes(ref bin) => &bin,
_ => panic!(),
}
}
}
#[test]
fn test_static_str() {
assert_eq!(Binary::from("test").len(), 4);
assert_eq!(Binary::from("test").as_ref(), b"test");
assert_eq!(Body::from("").length(), BodyLength::Sized(0));
assert_eq!(Body::from("test").length(), BodyLength::Sized(4));
assert_eq!(Body::from("test").get_ref(), b"test");
}
#[test]
fn test_static_bytes() {
assert_eq!(Binary::from(b"test".as_ref()).len(), 4);
assert_eq!(Binary::from(b"test".as_ref()).as_ref(), b"test");
assert_eq!(Binary::from_slice(b"test".as_ref()).len(), 4);
assert_eq!(Binary::from_slice(b"test".as_ref()).as_ref(), b"test");
assert_eq!(Body::from(b"test".as_ref()).length(), BodyLength::Sized(4));
assert_eq!(Body::from(b"test".as_ref()).get_ref(), b"test");
assert_eq!(
Body::from_slice(b"test".as_ref()).length(),
BodyLength::Sized(4)
);
assert_eq!(Body::from_slice(b"test".as_ref()).get_ref(), b"test");
}
#[test]
fn test_vec() {
assert_eq!(Binary::from(Vec::from("test")).len(), 4);
assert_eq!(Binary::from(Vec::from("test")).as_ref(), b"test");
assert_eq!(Body::from(Vec::from("test")).length(), BodyLength::Sized(4));
assert_eq!(Body::from(Vec::from("test")).get_ref(), b"test");
}
#[test]
fn test_bytes() {
assert_eq!(Binary::from(Bytes::from("test")).len(), 4);
assert_eq!(Binary::from(Bytes::from("test")).as_ref(), b"test");
}
#[test]
fn test_arc_string() {
let b = Arc::new("test".to_owned());
assert_eq!(Binary::from(b.clone()).len(), 4);
assert_eq!(Binary::from(b.clone()).as_ref(), b"test");
assert_eq!(Binary::from(&b).len(), 4);
assert_eq!(Binary::from(&b).as_ref(), b"test");
assert_eq!(
Body::from(Bytes::from("test")).length(),
BodyLength::Sized(4)
);
assert_eq!(Body::from(Bytes::from("test")).get_ref(), b"test");
}
#[test]
fn test_string() {
let b = "test".to_owned();
assert_eq!(Binary::from(b.clone()).len(), 4);
assert_eq!(Binary::from(b.clone()).as_ref(), b"test");
assert_eq!(Binary::from(&b).len(), 4);
assert_eq!(Binary::from(&b).as_ref(), b"test");
}
#[test]
fn test_shared_vec() {
let b = Arc::new(Vec::from(&b"test"[..]));
assert_eq!(Binary::from(b.clone()).len(), 4);
assert_eq!(Binary::from(b.clone()).as_ref(), &b"test"[..]);
assert_eq!(Binary::from(&b).len(), 4);
assert_eq!(Binary::from(&b).as_ref(), &b"test"[..]);
assert_eq!(Body::from(b.clone()).length(), BodyLength::Sized(4));
assert_eq!(Body::from(b.clone()).get_ref(), b"test");
assert_eq!(Body::from(&b).length(), BodyLength::Sized(4));
assert_eq!(Body::from(&b).get_ref(), b"test");
}
#[test]
fn test_bytes_mut() {
let b = BytesMut::from("test");
assert_eq!(Binary::from(b.clone()).len(), 4);
assert_eq!(Binary::from(b).as_ref(), b"test");
}
#[test]
fn test_binary_into() {
let bytes = Bytes::from_static(b"test");
let b: Bytes = Binary::from("test").into();
assert_eq!(b, bytes);
let b: Bytes = Binary::from(bytes.clone()).into();
assert_eq!(b, bytes);
assert_eq!(Body::from(b.clone()).length(), BodyLength::Sized(4));
assert_eq!(Body::from(b).get_ref(), b"test");
}
}

View File

@ -36,7 +36,9 @@ where
.and_then(|framed| framed.send((head, len).into()).from_err())
// send request body
.and_then(move |framed| match body.length() {
BodyLength::None | BodyLength::Zero => Either::A(ok(framed)),
BodyLength::None | BodyLength::Empty | BodyLength::Sized(0) => {
Either::A(ok(framed))
}
_ => Either::B(SendBody::new(body, framed)),
})
// read response and init read body

View File

@ -9,7 +9,7 @@ use futures::{Future, Stream};
use percent_encoding::{percent_encode, USERINFO_ENCODE_SET};
use urlcrate::Url;
use body::{MessageBody, MessageBodyStream};
use body::{BodyStream, MessageBody};
use error::Error;
use header::{self, Header, IntoHeaderValue};
use http::{
@ -534,14 +534,15 @@ impl ClientRequestBuilder {
/// Set an streaming body and generate `ClientRequest`.
///
/// `ClientRequestBuilder` can not be used after this call.
pub fn stream<S>(
pub fn stream<S, E>(
&mut self,
stream: S,
) -> Result<ClientRequest<impl MessageBody>, HttpError>
where
S: Stream<Item = Bytes, Error = Error>,
S: Stream<Item = Bytes, Error = E>,
E: Into<Error> + 'static,
{
self.body(MessageBodyStream::new(stream))
self.body(BodyStream::new(stream))
}
/// Set an empty body and generate `ClientRequest`.

View File

@ -20,6 +20,7 @@ use tokio_timer::Error as TimerError;
// re-exports
pub use cookie::ParseError as CookieParseError;
use body::Body;
use response::{Response, ResponseParts};
/// A specialized [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html)
@ -100,10 +101,10 @@ impl Error {
}
/// Converts error to a response instance and set error message as response body
pub fn response_with_message(self) -> Response<String> {
pub fn response_with_message(self) -> Response {
let message = format!("{}", self);
let resp: Response = self.into();
resp.set_body(message)
resp.set_body(Body::from(message))
}
}

View File

@ -7,7 +7,7 @@ use tokio_codec::{Decoder, Encoder};
use super::decoder::{MessageDecoder, PayloadDecoder, PayloadItem, PayloadType};
use super::encoder::RequestEncoder;
use super::{Message, MessageType};
use body::{Binary, BodyLength};
use body::BodyLength;
use client::ClientResponse;
use config::ServiceConfig;
use error::{ParseError, PayloadError};
@ -167,7 +167,7 @@ impl ClientCodecInner {
BodyLength::Chunked => {
buffer.extend_from_slice(b"\r\ntransfer-encoding: chunked\r\n")
}
BodyLength::Zero => {
BodyLength::Empty => {
len_is_set = false;
buffer.extend_from_slice(b"\r\n")
}
@ -183,7 +183,7 @@ impl ClientCodecInner {
TRANSFER_ENCODING => continue,
CONTENT_LENGTH => match length {
BodyLength::None => (),
BodyLength::Zero => len_is_set = true,
BodyLength::Empty => len_is_set = true,
_ => continue,
},
DATE => has_date = true,

View File

@ -8,7 +8,7 @@ use tokio_codec::{Decoder, Encoder};
use super::decoder::{MessageDecoder, PayloadDecoder, PayloadItem, PayloadType};
use super::encoder::ResponseEncoder;
use super::{Message, MessageType};
use body::{Binary, BodyLength};
use body::BodyLength;
use config::ServiceConfig;
use error::ParseError;
use helpers;
@ -106,7 +106,7 @@ impl Codec {
fn encode_response(
&mut self,
mut msg: Response,
mut msg: Response<()>,
buffer: &mut BytesMut,
) -> io::Result<()> {
let ka = self.flags.contains(Flags::KEEPALIVE_ENABLED) && msg
@ -149,7 +149,7 @@ impl Codec {
BodyLength::Chunked => {
buffer.extend_from_slice(b"\r\ntransfer-encoding: chunked\r\n")
}
BodyLength::Zero => {
BodyLength::Empty => {
len_is_set = false;
buffer.extend_from_slice(b"\r\n")
}
@ -174,7 +174,7 @@ impl Codec {
TRANSFER_ENCODING => continue,
CONTENT_LENGTH => match self.te.length {
BodyLength::None => (),
BodyLength::Zero => {
BodyLength::Empty => {
len_is_set = true;
}
_ => continue,
@ -268,7 +268,7 @@ impl Decoder for Codec {
}
impl Encoder for Codec {
type Item = Message<Response>;
type Item = Message<Response<()>>;
type Error = io::Error;
fn encode(

View File

@ -65,7 +65,7 @@ where
enum DispatcherMessage {
Item(Request),
Error(Response),
Error(Response<()>),
}
enum State<S: Service, B: MessageBody> {
@ -190,7 +190,7 @@ where
fn send_response<B1: MessageBody>(
&mut self,
message: Response,
message: Response<()>,
body: B1,
) -> Result<State<S, B1>, DispatchError<S::Error>> {
self.framed
@ -206,7 +206,7 @@ where
.set(Flags::KEEPALIVE, self.framed.get_codec().keepalive());
self.flags.remove(Flags::FLUSHED);
match body.length() {
BodyLength::None | BodyLength::Zero => Ok(State::None),
BodyLength::None | BodyLength::Empty => Ok(State::None),
_ => Ok(State::SendPayload(body)),
}
}
@ -351,7 +351,7 @@ where
);
self.flags.insert(Flags::DISCONNECTED);
self.messages.push_back(DispatcherMessage::Error(
Response::InternalServerError().finish(),
Response::InternalServerError().finish().drop_body(),
));
self.error = Some(DispatchError::InternalError);
break;
@ -364,7 +364,7 @@ where
error!("Internal server error: unexpected eof");
self.flags.insert(Flags::DISCONNECTED);
self.messages.push_back(DispatcherMessage::Error(
Response::InternalServerError().finish(),
Response::InternalServerError().finish().drop_body(),
));
self.error = Some(DispatchError::InternalError);
break;
@ -389,7 +389,7 @@ where
// Malformed requests should be responded with 400
self.messages.push_back(DispatcherMessage::Error(
Response::BadRequest().finish(),
Response::BadRequest().finish().drop_body(),
));
self.flags.insert(Flags::DISCONNECTED);
self.error = Some(e.into());
@ -440,8 +440,10 @@ where
// timeout on first request (slow request) return 408
trace!("Slow request timeout");
self.flags.insert(Flags::STARTED | Flags::DISCONNECTED);
let _ = self
.send_response(Response::RequestTimeout().finish(), ());
let _ = self.send_response(
Response::RequestTimeout().finish().drop_body(),
(),
);
self.state = State::None;
}
} else if let Some(deadline) = self.config.keep_alive_expire() {

View File

@ -8,7 +8,7 @@ use bytes::{Bytes, BytesMut};
use http::header::{HeaderValue, ACCEPT_ENCODING, CONTENT_LENGTH};
use http::{StatusCode, Version};
use body::{Binary, BodyLength};
use body::BodyLength;
use header::ContentEncoding;
use http::Method;
use message::{RequestHead, ResponseHead};
@ -52,7 +52,7 @@ impl ResponseEncoder {
) {
self.head = head;
let transfer = match length {
BodyLength::Zero => {
BodyLength::Empty => {
match resp.status {
StatusCode::NO_CONTENT
| StatusCode::CONTINUE

View File

@ -109,7 +109,7 @@ extern crate serde_derive;
#[cfg(feature = "ssl")]
extern crate openssl;
mod body;
pub mod body;
pub mod client;
mod config;
mod extensions;
@ -129,7 +129,7 @@ pub mod h1;
pub(crate) mod helpers;
pub mod test;
pub mod ws;
pub use body::{Binary, MessageBody};
pub use body::{Body, MessageBody};
pub use error::{Error, ResponseError, Result};
pub use extensions::Extensions;
pub use httpmessage::HttpMessage;
@ -150,7 +150,6 @@ pub mod dev {
//! use actix_http::dev::*;
//! ```
pub use body::BodyStream;
pub use httpmessage::{MessageBody, Readlines, UrlEncoded};
pub use json::JsonBody;
pub use payload::{Payload, PayloadBuffer};

View File

@ -12,9 +12,9 @@ use http::{Error as HttpError, HeaderMap, HttpTryFrom, StatusCode, Version};
use serde::Serialize;
use serde_json;
use body::{MessageBody, MessageBodyStream};
use body::{Body, BodyStream, MessageBody};
use error::Error;
use header::{ContentEncoding, Header, IntoHeaderValue};
use header::{Header, IntoHeaderValue};
use message::{Head, MessageFlags, ResponseHead};
/// max write buffer size 64k
@ -32,9 +32,9 @@ pub enum ConnectionType {
}
/// An HTTP Response
pub struct Response<B: MessageBody = ()>(Box<InnerResponse>, B);
pub struct Response<B: MessageBody = Body>(Box<InnerResponse>, B);
impl Response<()> {
impl Response<Body> {
/// Create http response builder with specific status.
#[inline]
pub fn build(status: StatusCode) -> ResponseBuilder {
@ -50,7 +50,7 @@ impl Response<()> {
/// Constructs a response
#[inline]
pub fn new(status: StatusCode) -> Response {
ResponsePool::with_body(status, ())
ResponsePool::with_body(status, Body::Empty)
}
/// Constructs an error response
@ -242,6 +242,11 @@ impl<B: MessageBody> Response<B> {
Response(self.0, body)
}
/// Drop request's body
pub fn drop_body(self) -> Response<()> {
Response(self.0, ())
}
/// Set a body and return previous body value
pub fn replace_body<B2: MessageBody>(self, body: B2) -> (Response<B2>, B) {
(Response(self.0, body), self.1)
@ -252,7 +257,7 @@ impl<B: MessageBody> Response<B> {
self.get_ref().response_size
}
/// Set content encoding
/// Set response size
pub(crate) fn set_response_size(&mut self, size: u64) {
self.get_mut().response_size = size;
}
@ -266,7 +271,7 @@ impl<B: MessageBody> Response<B> {
}
pub(crate) fn from_parts(parts: ResponseParts) -> Response {
Response(Box::new(InnerResponse::from_parts(parts)), ())
Response(Box::new(InnerResponse::from_parts(parts)), Body::Empty)
}
}
@ -279,7 +284,6 @@ impl fmt::Debug for Response {
self.get_ref().head.status,
self.get_ref().head.reason.unwrap_or("")
);
let _ = writeln!(f, " encoding: {:?}", self.get_ref().encoding);
let _ = writeln!(f, " headers:");
for (key, val) in self.get_ref().head.headers.iter() {
let _ = writeln!(f, " {:?}: {:?}", key, val);
@ -396,20 +400,6 @@ impl ResponseBuilder {
self
}
/// Set content encoding.
///
/// By default `ContentEncoding::Auto` is used, which automatically
/// negotiates content encoding based on request's `Accept-Encoding`
/// headers. To enforce specific encoding, use specific
/// ContentEncoding` value.
#[inline]
pub fn content_encoding(&mut self, enc: ContentEncoding) -> &mut Self {
if let Some(parts) = parts(&mut self.response, &self.err) {
parts.encoding = Some(enc);
}
self
}
/// Set connection type
#[inline]
#[doc(hidden)]
@ -558,7 +548,14 @@ impl ResponseBuilder {
/// Set a body and generate `Response`.
///
/// `ResponseBuilder` can not be used after this call.
pub fn body<B: MessageBody>(&mut self, body: B) -> Response<B> {
pub fn body<B: Into<Body>>(&mut self, body: B) -> Response {
self.message_body(body.into())
}
/// Set a body and generate `Response`.
///
/// `ResponseBuilder` can not be used after this call.
pub fn message_body<B: MessageBody>(&mut self, body: B) -> Response<B> {
let mut error = if let Some(e) = self.err.take() {
Some(Error::from(e))
} else {
@ -589,25 +586,25 @@ impl ResponseBuilder {
/// Set a streaming body and generate `Response`.
///
/// `ResponseBuilder` can not be used after this call.
pub fn streaming<S, E>(&mut self, stream: S) -> Response<impl MessageBody>
pub fn streaming<S, E>(&mut self, stream: S) -> Response
where
S: Stream<Item = Bytes, Error = E> + 'static,
E: Into<Error>,
E: Into<Error> + 'static,
{
self.body(MessageBodyStream::new(stream.map_err(|e| e.into())))
self.body(Body::from_message(BodyStream::new(stream)))
}
/// Set a json body and generate `Response`
///
/// `ResponseBuilder` can not be used after this call.
pub fn json<T: Serialize>(&mut self, value: T) -> Response<String> {
pub fn json<T: Serialize>(&mut self, value: T) -> Response {
self.json2(&value)
}
/// Set a json body and generate `Response`
///
/// `ResponseBuilder` can not be used after this call.
pub fn json2<T: Serialize>(&mut self, value: &T) -> Response<String> {
pub fn json2<T: Serialize>(&mut self, value: &T) -> Response {
match serde_json::to_string(value) {
Ok(body) => {
let contains = if let Some(parts) = parts(&mut self.response, &self.err)
@ -620,12 +617,9 @@ impl ResponseBuilder {
self.header(header::CONTENT_TYPE, "application/json");
}
self.body(body)
}
Err(e) => {
let mut res: Response = Error::from(e).into();
res.replace_body(String::new()).0
self.body(Body::from(body))
}
Err(e) => Error::from(e).into(),
}
}
@ -633,8 +627,8 @@ impl ResponseBuilder {
/// Set an empty body and generate `Response`
///
/// `ResponseBuilder` can not be used after this call.
pub fn finish(&mut self) -> Response<()> {
self.body(())
pub fn finish(&mut self) -> Response {
self.body(Body::Empty)
}
/// This method construct new `ResponseBuilder`
@ -675,7 +669,7 @@ impl From<ResponseBuilder> for Response {
}
}
impl From<&'static str> for Response<&'static str> {
impl From<&'static str> for Response {
fn from(val: &'static str) -> Self {
Response::Ok()
.content_type("text/plain; charset=utf-8")
@ -683,7 +677,7 @@ impl From<&'static str> for Response<&'static str> {
}
}
impl From<&'static [u8]> for Response<&'static [u8]> {
impl From<&'static [u8]> for Response {
fn from(val: &'static [u8]) -> Self {
Response::Ok()
.content_type("application/octet-stream")
@ -691,7 +685,7 @@ impl From<&'static [u8]> for Response<&'static [u8]> {
}
}
impl From<String> for Response<String> {
impl From<String> for Response {
fn from(val: String) -> Self {
Response::Ok()
.content_type("text/plain; charset=utf-8")
@ -699,7 +693,15 @@ impl From<String> for Response<String> {
}
}
impl From<Bytes> for Response<Bytes> {
impl<'a> From<&'a String> for Response {
fn from(val: &'a String) -> Self {
Response::Ok()
.content_type("text/plain; charset=utf-8")
.body(val)
}
}
impl From<Bytes> for Response {
fn from(val: Bytes) -> Self {
Response::Ok()
.content_type("application/octet-stream")
@ -707,7 +709,7 @@ impl From<Bytes> for Response<Bytes> {
}
}
impl From<BytesMut> for Response<BytesMut> {
impl From<BytesMut> for Response {
fn from(val: BytesMut) -> Self {
Response::Ok()
.content_type("application/octet-stream")
@ -717,7 +719,6 @@ impl From<BytesMut> for Response<BytesMut> {
struct InnerResponse {
head: ResponseHead,
encoding: Option<ContentEncoding>,
connection_type: Option<ConnectionType>,
write_capacity: usize,
response_size: u64,
@ -727,7 +728,6 @@ struct InnerResponse {
pub(crate) struct ResponseParts {
head: ResponseHead,
encoding: Option<ContentEncoding>,
connection_type: Option<ConnectionType>,
error: Option<Error>,
}
@ -744,7 +744,6 @@ impl InnerResponse {
flags: MessageFlags::empty(),
},
pool,
encoding: None,
connection_type: None,
response_size: 0,
write_capacity: MAX_WRITE_BUFFER_SIZE,
@ -756,7 +755,6 @@ impl InnerResponse {
fn into_parts(self) -> ResponseParts {
ResponseParts {
head: self.head,
encoding: self.encoding,
connection_type: self.connection_type,
error: self.error,
}
@ -765,7 +763,6 @@ impl InnerResponse {
fn from_parts(parts: ResponseParts) -> InnerResponse {
InnerResponse {
head: parts.head,
encoding: parts.encoding,
connection_type: parts.connection_type,
response_size: 0,
write_capacity: MAX_WRITE_BUFFER_SIZE,
@ -841,7 +838,6 @@ impl ResponsePool {
let mut p = inner.pool.0.borrow_mut();
if p.len() < 128 {
inner.head.clear();
inner.encoding = None;
inner.connection_type = None;
inner.response_size = 0;
inner.error = None;
@ -854,11 +850,10 @@ impl ResponsePool {
#[cfg(test)]
mod tests {
use super::*;
use body::Binary;
use body::Body;
use http;
use http::header::{HeaderValue, CONTENT_TYPE, COOKIE};
use header::ContentEncoding;
// use test::TestRequest;
#[test]
@ -953,24 +948,24 @@ mod tests {
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "text/plain")
}
#[test]
fn test_content_encoding() {
let resp = Response::build(StatusCode::OK).finish();
assert_eq!(resp.content_encoding(), None);
// #[test]
// fn test_content_encoding() {
// let resp = Response::build(StatusCode::OK).finish();
// assert_eq!(resp.content_encoding(), None);
#[cfg(feature = "brotli")]
{
let resp = Response::build(StatusCode::OK)
.content_encoding(ContentEncoding::Br)
.finish();
assert_eq!(resp.content_encoding(), Some(ContentEncoding::Br));
}
// #[cfg(feature = "brotli")]
// {
// let resp = Response::build(StatusCode::OK)
// .content_encoding(ContentEncoding::Br)
// .finish();
// assert_eq!(resp.content_encoding(), Some(ContentEncoding::Br));
// }
let resp = Response::build(StatusCode::OK)
.content_encoding(ContentEncoding::Gzip)
.finish();
assert_eq!(resp.content_encoding(), Some(ContentEncoding::Gzip));
}
// let resp = Response::build(StatusCode::OK)
// .content_encoding(ContentEncoding::Gzip)
// .finish();
// assert_eq!(resp.content_encoding(), Some(ContentEncoding::Gzip));
// }
#[test]
fn test_json() {
@ -1020,15 +1015,6 @@ mod tests {
);
}
impl Body {
pub(crate) fn bin_ref(&self) -> &Binary {
match *self {
Body::Binary(ref bin) => bin,
_ => panic!(),
}
}
}
#[test]
fn test_into_response() {
let resp: Response = "test".into();
@ -1038,7 +1024,7 @@ mod tests {
HeaderValue::from_static("text/plain; charset=utf-8")
);
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(resp.body().bin_ref(), &Binary::from("test"));
assert_eq!(resp.body().get_ref(), b"test");
let resp: Response = b"test".as_ref().into();
assert_eq!(resp.status(), StatusCode::OK);
@ -1047,7 +1033,7 @@ mod tests {
HeaderValue::from_static("application/octet-stream")
);
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(resp.body().bin_ref(), &Binary::from(b"test".as_ref()));
assert_eq!(resp.body().get_ref(), b"test");
let resp: Response = "test".to_owned().into();
assert_eq!(resp.status(), StatusCode::OK);
@ -1056,7 +1042,7 @@ mod tests {
HeaderValue::from_static("text/plain; charset=utf-8")
);
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(resp.body().bin_ref(), &Binary::from("test".to_owned()));
assert_eq!(resp.body().get_ref(), b"test");
let resp: Response = (&"test".to_owned()).into();
assert_eq!(resp.status(), StatusCode::OK);
@ -1065,7 +1051,7 @@ mod tests {
HeaderValue::from_static("text/plain; charset=utf-8")
);
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(resp.body().bin_ref(), &Binary::from(&"test".to_owned()));
assert_eq!(resp.body().get_ref(), b"test");
let b = Bytes::from_static(b"test");
let resp: Response = b.into();
@ -1075,10 +1061,7 @@ mod tests {
HeaderValue::from_static("application/octet-stream")
);
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(
resp.body().bin_ref(),
&Binary::from(Bytes::from_static(b"test"))
);
assert_eq!(resp.body().get_ref(), b"test");
let b = Bytes::from_static(b"test");
let resp: Response = b.into();
@ -1088,7 +1071,7 @@ mod tests {
HeaderValue::from_static("application/octet-stream")
);
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(resp.body().bin_ref(), &Binary::from(BytesMut::from("test")));
assert_eq!(resp.body().get_ref(), b"test");
let b = BytesMut::from("test");
let resp: Response = b.into();
@ -1098,7 +1081,7 @@ mod tests {
HeaderValue::from_static("application/octet-stream")
);
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(resp.body().bin_ref(), &Binary::from(BytesMut::from("test")));
assert_eq!(resp.body().get_ref(), b"test");
}
#[test]

View File

@ -72,7 +72,7 @@ where
}
pub struct SendErrorFut<T, R, E> {
res: Option<Message<Response>>,
res: Option<Message<Response<()>>>,
framed: Option<Framed<T, Codec>>,
err: Option<E>,
_t: PhantomData<R>,
@ -188,7 +188,7 @@ where
}
pub struct SendResponseFut<T, B> {
res: Option<Message<Response>>,
res: Option<Message<Response<()>>>,
body: Option<B>,
framed: Option<Framed<T, Codec>>,
}

View File

@ -4,6 +4,7 @@ use std::str::FromStr;
use actix::System;
use bytes::Bytes;
use cookie::Cookie;
use futures::Future;
use http::header::HeaderName;
@ -11,7 +12,6 @@ use http::{HeaderMap, HttpTryFrom, Method, Uri, Version};
use net2::TcpBuilder;
use tokio::runtime::current_thread::Runtime;
use body::Binary;
use header::{Header, IntoHeaderValue};
use payload::Payload;
use request::Request;
@ -362,10 +362,9 @@ impl TestRequest {
}
/// Set request payload
pub fn set_payload<B: Into<Binary>>(mut self, data: B) -> Self {
let mut data = data.into();
pub fn set_payload<B: Into<Bytes>>(mut self, data: B) -> Self {
let mut payload = Payload::empty();
payload.unread_data(data.take());
payload.unread_data(data.into());
self.payload = Some(payload);
self
}

View File

@ -1,10 +1,9 @@
use bytes::BytesMut;
use bytes::{Bytes, BytesMut};
use tokio_codec::{Decoder, Encoder};
use super::frame::Parser;
use super::proto::{CloseReason, OpCode};
use super::ProtocolError;
use body::Binary;
/// `WebSocket` Message
#[derive(Debug, PartialEq)]
@ -12,7 +11,7 @@ pub enum Message {
/// Text message
Text(String),
/// Binary message
Binary(Binary),
Binary(Bytes),
/// Ping message
Ping(String),
/// Pong message

View File

@ -1,8 +1,7 @@
use byteorder::{ByteOrder, LittleEndian, NetworkEndian};
use bytes::{BufMut, BytesMut};
use bytes::{BufMut, Bytes, BytesMut};
use rand;
use body::Binary;
use ws::mask::apply_mask;
use ws::proto::{CloseCode, CloseReason, OpCode};
use ws::ProtocolError;
@ -151,7 +150,7 @@ impl Parser {
}
/// Generate binary representation
pub fn write_message<B: Into<Binary>>(
pub fn write_message<B: Into<Bytes>>(
dst: &mut BytesMut,
pl: B,
op: OpCode,

View File

@ -15,7 +15,7 @@ use bytes::Bytes;
use futures::future::{self, ok};
use futures::stream::once;
use actix_http::{h1, http, Body, KeepAlive, Request, Response};
use actix_http::{body, h1, http, Body, Error, KeepAlive, Request, Response};
#[test]
fn test_h1_v2() {
@ -349,11 +349,9 @@ fn test_body_length() {
.bind("test", addr, move || {
h1::H1Service::new(|_| {
let body = once(Ok(Bytes::from_static(STR.as_ref())));
ok::<_, ()>(
Response::Ok()
.content_length(STR.len() as u64)
.body(Body::Streaming(Box::new(body))),
)
ok::<_, ()>(Response::Ok().body(Body::from_message(
body::SizedStream::new(STR.len(), body),
)))
}).map(|_| ())
}).unwrap()
.run()
@ -379,12 +377,8 @@ fn test_body_chunked_explicit() {
Server::new()
.bind("test", addr, move || {
h1::H1Service::new(|_| {
let body = once(Ok(Bytes::from_static(STR.as_ref())));
ok::<_, ()>(
Response::Ok()
.chunked()
.body(Body::Streaming(Box::new(body))),
)
let body = once::<_, Error>(Ok(Bytes::from_static(STR.as_ref())));
ok::<_, ()>(Response::Ok().streaming(body))
}).map(|_| ())
}).unwrap()
.run()
@ -412,8 +406,8 @@ fn test_body_chunked_implicit() {
Server::new()
.bind("test", addr, move || {
h1::H1Service::new(|_| {
let body = once(Ok(Bytes::from_static(STR.as_ref())));
ok::<_, ()>(Response::Ok().body(Body::Streaming(Box::new(body))))
let body = once::<_, Error>(Ok(Bytes::from_static(STR.as_ref())));
ok::<_, ()>(Response::Ok().streaming(body))
}).map(|_| ())
}).unwrap()
.run()

View File

@ -18,7 +18,7 @@ use bytes::{Bytes, BytesMut};
use futures::future::{lazy, ok, Either};
use futures::{Future, IntoFuture, Sink, Stream};
use actix_http::{h1, ws, ResponseError, ServiceConfig};
use actix_http::{h1, ws, ResponseError, SendResponse, ServiceConfig};
fn ws_service(req: ws::Frame) -> impl Future<Item = ws::Message, Error = io::Error> {
match req {
@ -55,20 +55,19 @@ fn test_simple() {
match ws::verify_handshake(&req) {
Err(e) => {
// validation failed
let resp = e.error_response();
Either::A(
framed
.send(h1::Message::Item(resp))
SendResponse::send(framed, e.error_response())
.map_err(|_| ())
.map(|_| ()),
)
}
Ok(_) => Either::B(
// send response
framed
.send(h1::Message::Item(
Ok(_) => {
Either::B(
// send handshake response
SendResponse::send(
framed,
ws::handshake_response(&req).finish(),
)).map_err(|_| ())
).map_err(|_| ())
.and_then(|framed| {
// start websocket service
let framed =
@ -76,7 +75,8 @@ fn test_simple() {
ws::Transport::with(framed, ws_service)
.map_err(|_| ())
}),
),
)
}
}
} else {
panic!()