mirror of
https://github.com/fafhrd91/actix-web
synced 2024-11-23 16:21:06 +01:00
refactory response body
This commit is contained in:
parent
779b480663
commit
c435f16170
13
CHANGES.md
Normal file
13
CHANGES.md
Normal 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
|
@ -17,8 +17,8 @@ fn with_param(req: &mut HttpRequest, _payload: Payload, state: &()) -> HttpRespo
|
|||||||
|
|
||||||
HttpResponse::builder(StatusCode::OK)
|
HttpResponse::builder(StatusCode::OK)
|
||||||
.content_type("test/plain")
|
.content_type("test/plain")
|
||||||
.body(Body::Binary(
|
.body(format!("Hello {}!", req.match_info().get("name").unwrap()))
|
||||||
format!("Hello {}!", req.match_info().get("name").unwrap()).into())).unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -19,7 +19,7 @@ fn index(req: &mut HttpRequest, _: Payload, state: &AppState) -> HttpResponse {
|
|||||||
println!("{:?}", req);
|
println!("{:?}", req);
|
||||||
state.counter.set(state.counter.get() + 1);
|
state.counter.set(state.counter.get() + 1);
|
||||||
httpcodes::HTTPOk.with_body(
|
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,
|
/// `MyWebSocket` counts how many messages it receives from peer,
|
||||||
|
108
src/body.rs
Normal file
108
src/body.rs
Normal 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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,7 +11,8 @@ use http::{StatusCode, Error as HttpError};
|
|||||||
|
|
||||||
use HttpRangeParseError;
|
use HttpRangeParseError;
|
||||||
use multipart::MultipartError;
|
use multipart::MultipartError;
|
||||||
use httpresponse::{Body, HttpResponse};
|
use body::Body;
|
||||||
|
use httpresponse::{HttpResponse};
|
||||||
|
|
||||||
|
|
||||||
/// A set of errors that can occur during parsing HTTP streams.
|
/// A set of errors that can occur during parsing HTTP streams.
|
||||||
@ -139,8 +140,8 @@ impl From<MultipartError> for HttpResponse {
|
|||||||
/// Return `BadRequest` for `HttpRangeParseError`
|
/// Return `BadRequest` for `HttpRangeParseError`
|
||||||
impl From<HttpRangeParseError> for HttpResponse {
|
impl From<HttpRangeParseError> for HttpResponse {
|
||||||
fn from(_: HttpRangeParseError) -> Self {
|
fn from(_: HttpRangeParseError) -> Self {
|
||||||
HttpResponse::new(StatusCode::BAD_REQUEST,
|
HttpResponse::new(
|
||||||
Body::Binary("Invalid Range header provided".into()))
|
StatusCode::BAD_REQUEST, Body::from("Invalid Range header provided"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,11 +3,12 @@
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use http::StatusCode;
|
use http::StatusCode;
|
||||||
|
|
||||||
|
use body::Body;
|
||||||
use task::Task;
|
use task::Task;
|
||||||
use route::RouteHandler;
|
use route::RouteHandler;
|
||||||
use payload::Payload;
|
use payload::Payload;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
use httpresponse::{Body, HttpResponse, HttpResponseBuilder};
|
use httpresponse::{HttpResponse, HttpResponseBuilder};
|
||||||
|
|
||||||
pub const HTTPOk: StaticResponse = StaticResponse(StatusCode::OK);
|
pub const HTTPOk: StaticResponse = StaticResponse(StatusCode::OK);
|
||||||
pub const HTTPCreated: StaticResponse = StaticResponse(StatusCode::CREATED);
|
pub const HTTPCreated: StaticResponse = StaticResponse(StatusCode::CREATED);
|
||||||
@ -64,8 +65,8 @@ impl StaticResponse {
|
|||||||
resp.set_reason(reason);
|
resp.set_reason(reason);
|
||||||
resp
|
resp
|
||||||
}
|
}
|
||||||
pub fn with_body(self, body: Body) -> HttpResponse {
|
pub fn with_body<B: Into<Body>>(self, body: B) -> HttpResponse {
|
||||||
HttpResponse::new(self.0, body)
|
HttpResponse::new(self.0, body.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,11 +4,11 @@ use std::error::Error as Error;
|
|||||||
use std::convert::Into;
|
use std::convert::Into;
|
||||||
|
|
||||||
use cookie::CookieJar;
|
use cookie::CookieJar;
|
||||||
use bytes::Bytes;
|
|
||||||
use http::{StatusCode, Version, HeaderMap, HttpTryFrom, Error as HttpError};
|
use http::{StatusCode, Version, HeaderMap, HttpTryFrom, Error as HttpError};
|
||||||
use http::header::{self, HeaderName, HeaderValue};
|
use http::header::{self, HeaderName, HeaderValue};
|
||||||
|
|
||||||
use Cookie;
|
use Cookie;
|
||||||
|
use body::Body;
|
||||||
|
|
||||||
|
|
||||||
/// Represents various types of connection
|
/// Represents various types of connection
|
||||||
@ -22,32 +22,6 @@ pub enum ConnectionType {
|
|||||||
Upgrade,
|
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)]
|
#[derive(Debug)]
|
||||||
/// An HTTP Response
|
/// An HTTP Response
|
||||||
pub struct HttpResponse {
|
pub struct HttpResponse {
|
||||||
@ -90,14 +64,12 @@ impl HttpResponse {
|
|||||||
/// Constructs a response from error
|
/// Constructs a response from error
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_error<E: Error + 'static>(status: StatusCode, error: E) -> HttpResponse {
|
pub fn from_error<E: Error + 'static>(status: StatusCode, error: E) -> HttpResponse {
|
||||||
let body = Body::Binary(error.description().into());
|
|
||||||
|
|
||||||
HttpResponse {
|
HttpResponse {
|
||||||
version: None,
|
version: None,
|
||||||
headers: Default::default(),
|
headers: Default::default(),
|
||||||
status: status,
|
status: status,
|
||||||
reason: None,
|
reason: None,
|
||||||
body: body,
|
body: Body::from_slice(error.description().as_ref()),
|
||||||
chunked: false,
|
chunked: false,
|
||||||
// compression: None,
|
// compression: None,
|
||||||
connection_type: None,
|
connection_type: None,
|
||||||
|
@ -22,6 +22,7 @@ extern crate url;
|
|||||||
extern crate actix;
|
extern crate actix;
|
||||||
|
|
||||||
mod application;
|
mod application;
|
||||||
|
mod body;
|
||||||
mod context;
|
mod context;
|
||||||
mod error;
|
mod error;
|
||||||
mod date;
|
mod date;
|
||||||
@ -45,9 +46,10 @@ pub mod dev;
|
|||||||
pub mod httpcodes;
|
pub mod httpcodes;
|
||||||
pub mod multipart;
|
pub mod multipart;
|
||||||
pub use error::ParseError;
|
pub use error::ParseError;
|
||||||
|
pub use body::{Body, BinaryBody};
|
||||||
pub use application::{Application, ApplicationBuilder, Middleware};
|
pub use application::{Application, ApplicationBuilder, Middleware};
|
||||||
pub use httprequest::{HttpRequest, UrlEncoded};
|
pub use httprequest::{HttpRequest, UrlEncoded};
|
||||||
pub use httpresponse::{Body, HttpResponse, HttpResponseBuilder};
|
pub use httpresponse::{HttpResponse, HttpResponseBuilder};
|
||||||
pub use payload::{Payload, PayloadItem, PayloadError};
|
pub use payload::{Payload, PayloadItem, PayloadError};
|
||||||
pub use route::{Route, RouteFactory, RouteHandler, RouteResult};
|
pub use route::{Route, RouteFactory, RouteHandler, RouteResult};
|
||||||
pub use resource::{Reply, Resource};
|
pub use resource::{Reply, Resource};
|
||||||
|
@ -12,7 +12,7 @@ use context::HttpContext;
|
|||||||
use resource::Reply;
|
use resource::Reply;
|
||||||
use payload::Payload;
|
use payload::Payload;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
use httpresponse::{Body, HttpResponse};
|
use httpresponse::HttpResponse;
|
||||||
use httpcodes::HTTPExpectationFailed;
|
use httpcodes::HTTPExpectationFailed;
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -55,12 +55,10 @@ pub trait Route: Actor {
|
|||||||
ctx.write("HTTP/1.1 100 Continue\r\n\r\n");
|
ctx.write("HTTP/1.1 100 Continue\r\n\r\n");
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(HTTPExpectationFailed.with_body(
|
Err(HTTPExpectationFailed.with_body("Unknown Expect"))
|
||||||
Body::Binary("Unknown Expect".into())))
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(HTTPExpectationFailed.with_body(
|
Err(HTTPExpectationFailed.with_body("Unknown Expect"))
|
||||||
Body::Binary("Unknown Expect".into())))
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -14,7 +14,7 @@ use route::RouteHandler;
|
|||||||
use payload::Payload;
|
use payload::Payload;
|
||||||
use mime_guess::get_mime_type;
|
use mime_guess::get_mime_type;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
use httpresponse::{Body, HttpResponse};
|
use httpresponse::HttpResponse;
|
||||||
use httpcodes::{HTTPOk, HTTPNotFound, HTTPForbidden, HTTPInternalServerError};
|
use httpcodes::{HTTPOk, HTTPNotFound, HTTPForbidden, HTTPInternalServerError};
|
||||||
|
|
||||||
/// Static files handling
|
/// Static files handling
|
||||||
@ -111,7 +111,7 @@ impl StaticFiles {
|
|||||||
Ok(
|
Ok(
|
||||||
HTTPOk.builder()
|
HTTPOk.builder()
|
||||||
.content_type("text/html; charset=utf-8")
|
.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) => {
|
Ok(mut file) => {
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
let _ = file.read_to_end(&mut data);
|
let _ = file.read_to_end(&mut data);
|
||||||
Task::reply(resp.body(Body::Binary(data.into())).unwrap())
|
Task::reply(resp.body(data).unwrap())
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
Task::reply(HTTPInternalServerError)
|
Task::reply(HTTPInternalServerError)
|
||||||
|
@ -11,10 +11,11 @@ use futures::{Async, Future, Poll, Stream};
|
|||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
use date;
|
use date;
|
||||||
|
use body::Body;
|
||||||
use route::Frame;
|
use route::Frame;
|
||||||
use application::Middleware;
|
use application::Middleware;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
use httpresponse::{Body, HttpResponse};
|
use httpresponse::HttpResponse;
|
||||||
|
|
||||||
type FrameStream = Stream<Item=Frame, Error=io::Error>;
|
type FrameStream = Stream<Item=Frame, Error=io::Error>;
|
||||||
const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific
|
const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific
|
||||||
@ -219,7 +220,7 @@ impl Task {
|
|||||||
self.buffer.extend(b"\r\n");
|
self.buffer.extend(b"\r\n");
|
||||||
|
|
||||||
if let Body::Binary(ref bytes) = body {
|
if let Body::Binary(ref bytes) = body {
|
||||||
self.buffer.extend(bytes);
|
self.buffer.extend_from_slice(bytes.as_ref());
|
||||||
self.prepared = Some(msg);
|
self.prepared = Some(msg);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -67,12 +67,13 @@ use futures::{Async, Poll, Stream};
|
|||||||
|
|
||||||
use actix::{Actor, ResponseType};
|
use actix::{Actor, ResponseType};
|
||||||
|
|
||||||
|
use body::Body;
|
||||||
use context::HttpContext;
|
use context::HttpContext;
|
||||||
use route::Route;
|
use route::Route;
|
||||||
use payload::Payload;
|
use payload::Payload;
|
||||||
use httpcodes::{HTTPBadRequest, HTTPMethodNotAllowed};
|
use httpcodes::{HTTPBadRequest, HTTPMethodNotAllowed};
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
use httpresponse::{Body, ConnectionType, HttpResponse};
|
use httpresponse::{ConnectionType, HttpResponse};
|
||||||
|
|
||||||
use wsframe;
|
use wsframe;
|
||||||
use wsproto::*;
|
use wsproto::*;
|
||||||
|
Loading…
Reference in New Issue
Block a user