mirror of
https://github.com/actix/actix-web.git
synced 2024-12-23 00:26:34 +00:00
refactory response body
This commit is contained in:
parent
779b480663
commit
c435f16170
12 changed files with 148 additions and 51 deletions
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)
|
||||
.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() {
|
||||
|
|
|
@ -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
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 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"))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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::*;
|
||||
|
|
Loading…
Reference in a new issue