1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-06-11 09:49:29 +00:00

refactory response body

This commit is contained in:
Nikolay Kim 2017-10-23 23:25:32 -07:00
parent 779b480663
commit c435f16170
12 changed files with 148 additions and 51 deletions

13
CHANGES.md Normal file
View file

@ -0,0 +1,13 @@
# CHANGES
## 0.2.0 (2017-10-xx)
* Refactor response `Body`
* Refactor `RouteRecognizer` usability
## 0.1.0 (2017-10-23)
* First release

View file

@ -17,8 +17,8 @@ fn with_param(req: &mut HttpRequest, _payload: Payload, state: &()) -> HttpRespo
HttpResponse::builder(StatusCode::OK)
.content_type("test/plain")
.body(Body::Binary(
format!("Hello {}!", req.match_info().get("name").unwrap()).into())).unwrap()
.body(format!("Hello {}!", req.match_info().get("name").unwrap()))
.unwrap()
}
fn main() {

View file

@ -19,7 +19,7 @@ fn index(req: &mut HttpRequest, _: Payload, state: &AppState) -> HttpResponse {
println!("{:?}", req);
state.counter.set(state.counter.get() + 1);
httpcodes::HTTPOk.with_body(
Body::Binary(format!("Num of requests: {}", state.counter.get()).into()))
format!("Num of requests: {}", state.counter.get()))
}
/// `MyWebSocket` counts how many messages it receives from peer,

108
src/body.rs Normal file
View file

@ -0,0 +1,108 @@
use std::rc::Rc;
use std::sync::Arc;
use bytes::Bytes;
/// Represents various types of http message body.
#[derive(Debug)]
pub enum Body {
/// Empty response. `Content-Length` header is set to `0`
Empty,
/// Specific response body.
Binary(BinaryBody),
/// Streaming response body with specified length.
Length(u64),
/// Unspecified streaming response. Developer is responsible for setting
/// right `Content-Length` or `Transfer-Encoding` headers.
Streaming,
/// Upgrade connection.
Upgrade,
}
/// Represents various types of binary body.
/// `Content-Length` header is set to length of the body.
#[derive(Debug)]
pub enum BinaryBody {
/// Bytes body
Bytes(Bytes),
/// Static slice
Slice(&'static [u8]),
/// Shared bytes body
SharedBytes(Rc<Bytes>),
/// Shared bytes body
#[doc(hidden)]
ArcSharedBytes(Arc<Bytes>),
}
impl Body {
/// Does this body have payload.
pub fn has_body(&self) -> bool {
match *self {
Body::Length(_) | Body::Streaming => true,
_ => false
}
}
/// Create body from static string
pub fn from_slice<'a>(s: &'a [u8]) -> Body {
Body::Binary(BinaryBody::Bytes(Bytes::from(s)))
}
}
impl From<&'static str> for Body {
fn from(s: &'static str) -> Body {
Body::Binary(BinaryBody::Slice(s.as_ref()))
}
}
impl From<&'static [u8]> for Body {
fn from(s: &'static [u8]) -> Body {
Body::Binary(BinaryBody::Slice(s))
}
}
impl From<Vec<u8>> for Body {
fn from(vec: Vec<u8>) -> Body {
Body::Binary(BinaryBody::Bytes(Bytes::from(vec)))
}
}
impl From<String> for Body {
fn from(s: String) -> Body {
Body::Binary(BinaryBody::Bytes(Bytes::from(s)))
}
}
impl From<Rc<Bytes>> for Body {
fn from(body: Rc<Bytes>) -> Body {
Body::Binary(BinaryBody::SharedBytes(body))
}
}
impl From<Arc<Bytes>> for Body {
fn from(body: Arc<Bytes>) -> Body {
Body::Binary(BinaryBody::ArcSharedBytes(body))
}
}
impl BinaryBody {
pub fn len(&self) -> usize {
match self {
&BinaryBody::Bytes(ref bytes) => bytes.len(),
&BinaryBody::Slice(slice) => slice.len(),
&BinaryBody::SharedBytes(ref bytes) => bytes.len(),
&BinaryBody::ArcSharedBytes(ref bytes) => bytes.len(),
}
}
}
impl AsRef<[u8]> for BinaryBody {
fn as_ref(&self) -> &[u8] {
match self {
&BinaryBody::Bytes(ref bytes) => bytes.as_ref(),
&BinaryBody::Slice(slice) => slice,
&BinaryBody::SharedBytes(ref bytes) => bytes.as_ref(),
&BinaryBody::ArcSharedBytes(ref bytes) => bytes.as_ref(),
}
}
}

View file

@ -11,7 +11,8 @@ use http::{StatusCode, Error as HttpError};
use HttpRangeParseError;
use multipart::MultipartError;
use httpresponse::{Body, HttpResponse};
use body::Body;
use httpresponse::{HttpResponse};
/// A set of errors that can occur during parsing HTTP streams.
@ -139,8 +140,8 @@ impl From<MultipartError> for HttpResponse {
/// Return `BadRequest` for `HttpRangeParseError`
impl From<HttpRangeParseError> for HttpResponse {
fn from(_: HttpRangeParseError) -> Self {
HttpResponse::new(StatusCode::BAD_REQUEST,
Body::Binary("Invalid Range header provided".into()))
HttpResponse::new(
StatusCode::BAD_REQUEST, Body::from("Invalid Range header provided"))
}
}

View file

@ -3,11 +3,12 @@
use std::rc::Rc;
use http::StatusCode;
use body::Body;
use task::Task;
use route::RouteHandler;
use payload::Payload;
use httprequest::HttpRequest;
use httpresponse::{Body, HttpResponse, HttpResponseBuilder};
use httpresponse::{HttpResponse, HttpResponseBuilder};
pub const HTTPOk: StaticResponse = StaticResponse(StatusCode::OK);
pub const HTTPCreated: StaticResponse = StaticResponse(StatusCode::CREATED);
@ -64,8 +65,8 @@ impl StaticResponse {
resp.set_reason(reason);
resp
}
pub fn with_body(self, body: Body) -> HttpResponse {
HttpResponse::new(self.0, body)
pub fn with_body<B: Into<Body>>(self, body: B) -> HttpResponse {
HttpResponse::new(self.0, body.into())
}
}

View file

@ -4,11 +4,11 @@ use std::error::Error as Error;
use std::convert::Into;
use cookie::CookieJar;
use bytes::Bytes;
use http::{StatusCode, Version, HeaderMap, HttpTryFrom, Error as HttpError};
use http::header::{self, HeaderName, HeaderValue};
use Cookie;
use body::Body;
/// Represents various types of connection
@ -22,32 +22,6 @@ pub enum ConnectionType {
Upgrade,
}
/// Represents various types of http message body.
#[derive(Debug)]
pub enum Body {
/// Empty response. `Content-Length` header is set to `0`
Empty,
/// Specific response body. `Content-Length` header is set to length of bytes.
Binary(Bytes),
/// Streaming response body with specified length.
Length(u64),
/// Unspecified streaming response. Developer is responsible for setting
/// right `Content-Length` or `Transfer-Encoding` headers.
Streaming,
/// Upgrade connection.
Upgrade,
}
impl Body {
/// Does this body have payload.
pub fn has_body(&self) -> bool {
match *self {
Body::Length(_) | Body::Streaming => true,
_ => false
}
}
}
#[derive(Debug)]
/// An HTTP Response
pub struct HttpResponse {
@ -90,14 +64,12 @@ impl HttpResponse {
/// Constructs a response from error
#[inline]
pub fn from_error<E: Error + 'static>(status: StatusCode, error: E) -> HttpResponse {
let body = Body::Binary(error.description().into());
HttpResponse {
version: None,
headers: Default::default(),
status: status,
reason: None,
body: body,
body: Body::from_slice(error.description().as_ref()),
chunked: false,
// compression: None,
connection_type: None,

View file

@ -22,6 +22,7 @@ extern crate url;
extern crate actix;
mod application;
mod body;
mod context;
mod error;
mod date;
@ -45,9 +46,10 @@ pub mod dev;
pub mod httpcodes;
pub mod multipart;
pub use error::ParseError;
pub use body::{Body, BinaryBody};
pub use application::{Application, ApplicationBuilder, Middleware};
pub use httprequest::{HttpRequest, UrlEncoded};
pub use httpresponse::{Body, HttpResponse, HttpResponseBuilder};
pub use httpresponse::{HttpResponse, HttpResponseBuilder};
pub use payload::{Payload, PayloadItem, PayloadError};
pub use route::{Route, RouteFactory, RouteHandler, RouteResult};
pub use resource::{Reply, Resource};

View file

@ -12,7 +12,7 @@ use context::HttpContext;
use resource::Reply;
use payload::Payload;
use httprequest::HttpRequest;
use httpresponse::{Body, HttpResponse};
use httpresponse::HttpResponse;
use httpcodes::HTTPExpectationFailed;
#[doc(hidden)]
@ -55,12 +55,10 @@ pub trait Route: Actor {
ctx.write("HTTP/1.1 100 Continue\r\n\r\n");
Ok(())
} else {
Err(HTTPExpectationFailed.with_body(
Body::Binary("Unknown Expect".into())))
Err(HTTPExpectationFailed.with_body("Unknown Expect"))
}
} else {
Err(HTTPExpectationFailed.with_body(
Body::Binary("Unknown Expect".into())))
Err(HTTPExpectationFailed.with_body("Unknown Expect"))
}
} else {
Ok(())

View file

@ -14,7 +14,7 @@ use route::RouteHandler;
use payload::Payload;
use mime_guess::get_mime_type;
use httprequest::HttpRequest;
use httpresponse::{Body, HttpResponse};
use httpresponse::HttpResponse;
use httpcodes::{HTTPOk, HTTPNotFound, HTTPForbidden, HTTPInternalServerError};
/// Static files handling
@ -111,7 +111,7 @@ impl StaticFiles {
Ok(
HTTPOk.builder()
.content_type("text/html; charset=utf-8")
.body(Body::Binary(html.into())).unwrap()
.body(html).unwrap()
)
}
@ -188,7 +188,7 @@ impl<S: 'static> RouteHandler<S> for StaticFiles {
Ok(mut file) => {
let mut data = Vec::new();
let _ = file.read_to_end(&mut data);
Task::reply(resp.body(Body::Binary(data.into())).unwrap())
Task::reply(resp.body(data).unwrap())
},
Err(err) => {
Task::reply(HTTPInternalServerError)

View file

@ -11,10 +11,11 @@ use futures::{Async, Future, Poll, Stream};
use tokio_io::{AsyncRead, AsyncWrite};
use date;
use body::Body;
use route::Frame;
use application::Middleware;
use httprequest::HttpRequest;
use httpresponse::{Body, HttpResponse};
use httpresponse::HttpResponse;
type FrameStream = Stream<Item=Frame, Error=io::Error>;
const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific
@ -219,7 +220,7 @@ impl Task {
self.buffer.extend(b"\r\n");
if let Body::Binary(ref bytes) = body {
self.buffer.extend(bytes);
self.buffer.extend_from_slice(bytes.as_ref());
self.prepared = Some(msg);
return
}

View file

@ -67,12 +67,13 @@ use futures::{Async, Poll, Stream};
use actix::{Actor, ResponseType};
use body::Body;
use context::HttpContext;
use route::Route;
use payload::Payload;
use httpcodes::{HTTPBadRequest, HTTPMethodNotAllowed};
use httprequest::HttpRequest;
use httpresponse::{Body, ConnectionType, HttpResponse};
use httpresponse::{ConnectionType, HttpResponse};
use wsframe;
use wsproto::*;