mirror of
https://github.com/actix/actix-web.git
synced 2024-11-20 08:31:09 +00:00
add h1::SendResponse future; renamed to MessageBody::size
This commit is contained in:
parent
046b7a1425
commit
9bb40c249f
15 changed files with 308 additions and 104 deletions
|
@ -67,7 +67,7 @@ ssl = ["openssl", "actix-server/ssl", "awc/ssl"]
|
|||
rust-tls = ["rustls", "actix-server/rust-tls"]
|
||||
|
||||
[dependencies]
|
||||
actix-codec = "0.1.1"
|
||||
actix-codec = "0.1.2"
|
||||
actix-service = "0.3.6"
|
||||
actix-utils = "0.3.4"
|
||||
actix-router = "0.1.2"
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
|
||||
* Allow to use custom service for upgrade requests
|
||||
|
||||
* Added `h1::SendResponse` future.
|
||||
|
||||
### Changed
|
||||
|
||||
* MessageBody::length() renamed to MessageBody::size() for consistency
|
||||
|
||||
|
||||
## [0.1.0-alpha.4] - 2019-04-08
|
||||
|
||||
|
|
|
@ -30,13 +30,13 @@ impl BodySize {
|
|||
|
||||
/// Type that provides this trait can be streamed to a peer.
|
||||
pub trait MessageBody {
|
||||
fn length(&self) -> BodySize;
|
||||
fn size(&self) -> BodySize;
|
||||
|
||||
fn poll_next(&mut self) -> Poll<Option<Bytes>, Error>;
|
||||
}
|
||||
|
||||
impl MessageBody for () {
|
||||
fn length(&self) -> BodySize {
|
||||
fn size(&self) -> BodySize {
|
||||
BodySize::Empty
|
||||
}
|
||||
|
||||
|
@ -46,8 +46,8 @@ impl MessageBody for () {
|
|||
}
|
||||
|
||||
impl<T: MessageBody> MessageBody for Box<T> {
|
||||
fn length(&self) -> BodySize {
|
||||
self.as_ref().length()
|
||||
fn size(&self) -> BodySize {
|
||||
self.as_ref().size()
|
||||
}
|
||||
|
||||
fn poll_next(&mut self) -> Poll<Option<Bytes>, Error> {
|
||||
|
@ -86,10 +86,10 @@ impl<B: MessageBody> ResponseBody<B> {
|
|||
}
|
||||
|
||||
impl<B: MessageBody> MessageBody for ResponseBody<B> {
|
||||
fn length(&self) -> BodySize {
|
||||
fn size(&self) -> BodySize {
|
||||
match self {
|
||||
ResponseBody::Body(ref body) => body.length(),
|
||||
ResponseBody::Other(ref body) => body.length(),
|
||||
ResponseBody::Body(ref body) => body.size(),
|
||||
ResponseBody::Other(ref body) => body.size(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,12 +135,12 @@ impl Body {
|
|||
}
|
||||
|
||||
impl MessageBody for Body {
|
||||
fn length(&self) -> BodySize {
|
||||
fn size(&self) -> BodySize {
|
||||
match self {
|
||||
Body::None => BodySize::None,
|
||||
Body::Empty => BodySize::Empty,
|
||||
Body::Bytes(ref bin) => BodySize::Sized(bin.len()),
|
||||
Body::Message(ref body) => body.length(),
|
||||
Body::Message(ref body) => body.size(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,7 +185,7 @@ 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::Empty => write!(f, "Body::Empty"),
|
||||
Body::Bytes(ref b) => write!(f, "Body::Bytes({:?})", b),
|
||||
Body::Message(_) => write!(f, "Body::Message(_)"),
|
||||
}
|
||||
|
@ -235,7 +235,7 @@ impl From<BytesMut> for Body {
|
|||
}
|
||||
|
||||
impl MessageBody for Bytes {
|
||||
fn length(&self) -> BodySize {
|
||||
fn size(&self) -> BodySize {
|
||||
BodySize::Sized(self.len())
|
||||
}
|
||||
|
||||
|
@ -249,7 +249,7 @@ impl MessageBody for Bytes {
|
|||
}
|
||||
|
||||
impl MessageBody for BytesMut {
|
||||
fn length(&self) -> BodySize {
|
||||
fn size(&self) -> BodySize {
|
||||
BodySize::Sized(self.len())
|
||||
}
|
||||
|
||||
|
@ -265,7 +265,7 @@ impl MessageBody for BytesMut {
|
|||
}
|
||||
|
||||
impl MessageBody for &'static str {
|
||||
fn length(&self) -> BodySize {
|
||||
fn size(&self) -> BodySize {
|
||||
BodySize::Sized(self.len())
|
||||
}
|
||||
|
||||
|
@ -281,7 +281,7 @@ impl MessageBody for &'static str {
|
|||
}
|
||||
|
||||
impl MessageBody for &'static [u8] {
|
||||
fn length(&self) -> BodySize {
|
||||
fn size(&self) -> BodySize {
|
||||
BodySize::Sized(self.len())
|
||||
}
|
||||
|
||||
|
@ -297,7 +297,7 @@ impl MessageBody for &'static [u8] {
|
|||
}
|
||||
|
||||
impl MessageBody for Vec<u8> {
|
||||
fn length(&self) -> BodySize {
|
||||
fn size(&self) -> BodySize {
|
||||
BodySize::Sized(self.len())
|
||||
}
|
||||
|
||||
|
@ -314,7 +314,7 @@ impl MessageBody for Vec<u8> {
|
|||
}
|
||||
|
||||
impl MessageBody for String {
|
||||
fn length(&self) -> BodySize {
|
||||
fn size(&self) -> BodySize {
|
||||
BodySize::Sized(self.len())
|
||||
}
|
||||
|
||||
|
@ -354,7 +354,7 @@ where
|
|||
S: Stream<Item = Bytes, Error = E>,
|
||||
E: Into<Error>,
|
||||
{
|
||||
fn length(&self) -> BodySize {
|
||||
fn size(&self) -> BodySize {
|
||||
BodySize::Stream
|
||||
}
|
||||
|
||||
|
@ -383,7 +383,7 @@ impl<S> MessageBody for SizedStream<S>
|
|||
where
|
||||
S: Stream<Item = Bytes, Error = Error>,
|
||||
{
|
||||
fn length(&self) -> BodySize {
|
||||
fn size(&self) -> BodySize {
|
||||
BodySize::Sized(self.size)
|
||||
}
|
||||
|
||||
|
@ -416,47 +416,117 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_static_str() {
|
||||
assert_eq!(Body::from("").length(), BodySize::Sized(0));
|
||||
assert_eq!(Body::from("test").length(), BodySize::Sized(4));
|
||||
assert_eq!(Body::from("").size(), BodySize::Sized(0));
|
||||
assert_eq!(Body::from("test").size(), BodySize::Sized(4));
|
||||
assert_eq!(Body::from("test").get_ref(), b"test");
|
||||
|
||||
assert_eq!("test".size(), BodySize::Sized(4));
|
||||
assert_eq!(
|
||||
"test".poll_next().unwrap(),
|
||||
Async::Ready(Some(Bytes::from("test")))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_static_bytes() {
|
||||
assert_eq!(Body::from(b"test".as_ref()).length(), BodySize::Sized(4));
|
||||
assert_eq!(Body::from(b"test".as_ref()).size(), BodySize::Sized(4));
|
||||
assert_eq!(Body::from(b"test".as_ref()).get_ref(), b"test");
|
||||
assert_eq!(
|
||||
Body::from_slice(b"test".as_ref()).length(),
|
||||
Body::from_slice(b"test".as_ref()).size(),
|
||||
BodySize::Sized(4)
|
||||
);
|
||||
assert_eq!(Body::from_slice(b"test".as_ref()).get_ref(), b"test");
|
||||
|
||||
assert_eq!((&b"test"[..]).size(), BodySize::Sized(4));
|
||||
assert_eq!(
|
||||
(&b"test"[..]).poll_next().unwrap(),
|
||||
Async::Ready(Some(Bytes::from("test")))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vec() {
|
||||
assert_eq!(Body::from(Vec::from("test")).length(), BodySize::Sized(4));
|
||||
assert_eq!(Body::from(Vec::from("test")).size(), BodySize::Sized(4));
|
||||
assert_eq!(Body::from(Vec::from("test")).get_ref(), b"test");
|
||||
|
||||
assert_eq!(Vec::from("test").size(), BodySize::Sized(4));
|
||||
assert_eq!(
|
||||
Vec::from("test").poll_next().unwrap(),
|
||||
Async::Ready(Some(Bytes::from("test")))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytes() {
|
||||
assert_eq!(Body::from(Bytes::from("test")).length(), BodySize::Sized(4));
|
||||
assert_eq!(Body::from(Bytes::from("test")).get_ref(), b"test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string() {
|
||||
let b = "test".to_owned();
|
||||
assert_eq!(Body::from(b.clone()).length(), BodySize::Sized(4));
|
||||
let mut b = Bytes::from("test");
|
||||
assert_eq!(Body::from(b.clone()).size(), BodySize::Sized(4));
|
||||
assert_eq!(Body::from(b.clone()).get_ref(), b"test");
|
||||
assert_eq!(Body::from(&b).length(), BodySize::Sized(4));
|
||||
assert_eq!(Body::from(&b).get_ref(), b"test");
|
||||
|
||||
assert_eq!(b.size(), BodySize::Sized(4));
|
||||
assert_eq!(
|
||||
b.poll_next().unwrap(),
|
||||
Async::Ready(Some(Bytes::from("test")))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytes_mut() {
|
||||
let b = BytesMut::from("test");
|
||||
assert_eq!(Body::from(b.clone()).length(), BodySize::Sized(4));
|
||||
assert_eq!(Body::from(b).get_ref(), b"test");
|
||||
let mut b = BytesMut::from("test");
|
||||
assert_eq!(Body::from(b.clone()).size(), BodySize::Sized(4));
|
||||
assert_eq!(Body::from(b.clone()).get_ref(), b"test");
|
||||
|
||||
assert_eq!(b.size(), BodySize::Sized(4));
|
||||
assert_eq!(
|
||||
b.poll_next().unwrap(),
|
||||
Async::Ready(Some(Bytes::from("test")))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string() {
|
||||
let mut b = "test".to_owned();
|
||||
assert_eq!(Body::from(b.clone()).size(), BodySize::Sized(4));
|
||||
assert_eq!(Body::from(b.clone()).get_ref(), b"test");
|
||||
assert_eq!(Body::from(&b).size(), BodySize::Sized(4));
|
||||
assert_eq!(Body::from(&b).get_ref(), b"test");
|
||||
|
||||
assert_eq!(b.size(), BodySize::Sized(4));
|
||||
assert_eq!(
|
||||
b.poll_next().unwrap(),
|
||||
Async::Ready(Some(Bytes::from("test")))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unit() {
|
||||
assert_eq!(().size(), BodySize::Empty);
|
||||
assert_eq!(().poll_next().unwrap(), Async::Ready(None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_box() {
|
||||
let mut val = Box::new(());
|
||||
assert_eq!(val.size(), BodySize::Empty);
|
||||
assert_eq!(val.poll_next().unwrap(), Async::Ready(None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_body_eq() {
|
||||
assert!(Body::None == Body::None);
|
||||
assert!(Body::None != Body::Empty);
|
||||
assert!(Body::Empty == Body::Empty);
|
||||
assert!(Body::Empty != Body::None);
|
||||
assert!(
|
||||
Body::Bytes(Bytes::from_static(b"1"))
|
||||
== Body::Bytes(Bytes::from_static(b"1"))
|
||||
);
|
||||
assert!(Body::Bytes(Bytes::from_static(b"1")) != Body::None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
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"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,14 +55,14 @@ where
|
|||
io: Some(io),
|
||||
};
|
||||
|
||||
let len = body.length();
|
||||
let len = body.size();
|
||||
|
||||
// create Framed and send reqest
|
||||
Framed::new(io, h1::ClientCodec::default())
|
||||
.send((head, len).into())
|
||||
.from_err()
|
||||
// send request body
|
||||
.and_then(move |framed| match body.length() {
|
||||
.and_then(move |framed| match body.size() {
|
||||
BodySize::None | BodySize::Empty | BodySize::Sized(0) => {
|
||||
Either::A(ok(framed))
|
||||
}
|
||||
|
|
|
@ -27,9 +27,9 @@ where
|
|||
T: AsyncRead + AsyncWrite + 'static,
|
||||
B: MessageBody,
|
||||
{
|
||||
trace!("Sending client request: {:?} {:?}", head, body.length());
|
||||
trace!("Sending client request: {:?} {:?}", head, body.size());
|
||||
let head_req = head.method == Method::HEAD;
|
||||
let length = body.length();
|
||||
let length = body.size();
|
||||
let eof = match length {
|
||||
BodySize::None | BodySize::Empty | BodySize::Sized(0) => true,
|
||||
_ => false,
|
||||
|
|
|
@ -79,12 +79,12 @@ enum EncoderBody<B> {
|
|||
}
|
||||
|
||||
impl<B: MessageBody> MessageBody for Encoder<B> {
|
||||
fn length(&self) -> BodySize {
|
||||
fn size(&self) -> BodySize {
|
||||
if self.encoder.is_none() {
|
||||
match self.body {
|
||||
EncoderBody::Bytes(ref b) => b.length(),
|
||||
EncoderBody::Stream(ref b) => b.length(),
|
||||
EncoderBody::BoxedStream(ref b) => b.length(),
|
||||
EncoderBody::Bytes(ref b) => b.size(),
|
||||
EncoderBody::Stream(ref b) => b.size(),
|
||||
EncoderBody::BoxedStream(ref b) => b.size(),
|
||||
}
|
||||
} else {
|
||||
BodySize::Stream
|
||||
|
|
|
@ -320,7 +320,7 @@ where
|
|||
body: ResponseBody<B>,
|
||||
) -> Result<State<S, B, X>, DispatchError> {
|
||||
self.codec
|
||||
.encode(Message::Item((message, body.length())), &mut self.write_buf)
|
||||
.encode(Message::Item((message, body.size())), &mut self.write_buf)
|
||||
.map_err(|err| {
|
||||
if let Some(mut payload) = self.payload.take() {
|
||||
payload.set_error(PayloadError::Incomplete(None));
|
||||
|
@ -329,7 +329,7 @@ where
|
|||
})?;
|
||||
|
||||
self.flags.set(Flags::KEEPALIVE, self.codec.keepalive());
|
||||
match body.length() {
|
||||
match body.size() {
|
||||
BodySize::None | BodySize::Empty => Ok(State::None),
|
||||
_ => Ok(State::SendPayload(body)),
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ mod expect;
|
|||
mod payload;
|
||||
mod service;
|
||||
mod upgrade;
|
||||
mod utils;
|
||||
|
||||
pub use self::client::{ClientCodec, ClientPayloadCodec};
|
||||
pub use self::codec::Codec;
|
||||
|
@ -18,6 +19,7 @@ pub use self::expect::ExpectHandler;
|
|||
pub use self::payload::Payload;
|
||||
pub use self::service::{H1Service, H1ServiceHandler, OneRequest};
|
||||
pub use self::upgrade::UpgradeHandler;
|
||||
pub use self::utils::SendResponse;
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Codec message
|
||||
|
|
92
actix-http/src/h1/utils.rs
Normal file
92
actix-http/src/h1/utils.rs
Normal file
|
@ -0,0 +1,92 @@
|
|||
use actix_codec::{AsyncRead, AsyncWrite, Framed};
|
||||
use futures::{Async, Future, Poll, Sink};
|
||||
|
||||
use crate::body::{BodySize, MessageBody, ResponseBody};
|
||||
use crate::error::Error;
|
||||
use crate::h1::{Codec, Message};
|
||||
use crate::response::Response;
|
||||
|
||||
/// Send http/1 response
|
||||
pub struct SendResponse<T, B> {
|
||||
res: Option<Message<(Response<()>, BodySize)>>,
|
||||
body: Option<ResponseBody<B>>,
|
||||
framed: Option<Framed<T, Codec>>,
|
||||
}
|
||||
|
||||
impl<T, B> SendResponse<T, B>
|
||||
where
|
||||
B: MessageBody,
|
||||
{
|
||||
pub fn new(framed: Framed<T, Codec>, response: Response<B>) -> Self {
|
||||
let (res, body) = response.into_parts();
|
||||
|
||||
SendResponse {
|
||||
res: Some((res, body.size()).into()),
|
||||
body: Some(body),
|
||||
framed: Some(framed),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, B> Future for SendResponse<T, B>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite,
|
||||
B: MessageBody,
|
||||
{
|
||||
type Item = Framed<T, Codec>;
|
||||
type Error = Error;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
loop {
|
||||
let mut body_ready = self.body.is_some();
|
||||
let framed = self.framed.as_mut().unwrap();
|
||||
|
||||
// send body
|
||||
if self.res.is_none() && self.body.is_some() {
|
||||
while body_ready && self.body.is_some() && !framed.is_write_buf_full() {
|
||||
match self.body.as_mut().unwrap().poll_next()? {
|
||||
Async::Ready(item) => {
|
||||
// body is done
|
||||
if item.is_none() {
|
||||
let _ = self.body.take();
|
||||
}
|
||||
framed.force_send(Message::Chunk(item))?;
|
||||
}
|
||||
Async::NotReady => body_ready = false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// flush write buffer
|
||||
if !framed.is_write_buf_empty() {
|
||||
match framed.poll_complete()? {
|
||||
Async::Ready(_) => {
|
||||
if body_ready {
|
||||
continue;
|
||||
} else {
|
||||
return Ok(Async::NotReady);
|
||||
}
|
||||
}
|
||||
Async::NotReady => return Ok(Async::NotReady),
|
||||
}
|
||||
}
|
||||
|
||||
// send response
|
||||
if let Some(res) = self.res.take() {
|
||||
framed.force_send(res)?;
|
||||
continue;
|
||||
}
|
||||
|
||||
if self.body.is_some() {
|
||||
if body_ready {
|
||||
continue;
|
||||
} else {
|
||||
return Ok(Async::NotReady);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(Async::Ready(self.framed.take().unwrap()))
|
||||
}
|
||||
}
|
|
@ -153,10 +153,10 @@ where
|
|||
fn prepare_response(
|
||||
&self,
|
||||
head: &ResponseHead,
|
||||
length: &mut BodySize,
|
||||
size: &mut BodySize,
|
||||
) -> http::Response<()> {
|
||||
let mut has_date = false;
|
||||
let mut skip_len = length != &BodySize::Stream;
|
||||
let mut skip_len = size != &BodySize::Stream;
|
||||
|
||||
let mut res = http::Response::new(());
|
||||
*res.status_mut() = head.status;
|
||||
|
@ -166,14 +166,14 @@ where
|
|||
match head.status {
|
||||
http::StatusCode::NO_CONTENT
|
||||
| http::StatusCode::CONTINUE
|
||||
| http::StatusCode::PROCESSING => *length = BodySize::None,
|
||||
| http::StatusCode::PROCESSING => *size = BodySize::None,
|
||||
http::StatusCode::SWITCHING_PROTOCOLS => {
|
||||
skip_len = true;
|
||||
*length = BodySize::Stream;
|
||||
*size = BodySize::Stream;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
let _ = match length {
|
||||
let _ = match size {
|
||||
BodySize::None | BodySize::Stream => None,
|
||||
BodySize::Empty => res
|
||||
.headers_mut()
|
||||
|
@ -229,16 +229,15 @@ where
|
|||
let (res, body) = res.into().replace_body(());
|
||||
|
||||
let mut send = send.take().unwrap();
|
||||
let mut length = body.length();
|
||||
let h2_res = self.prepare_response(res.head(), &mut length);
|
||||
let mut size = body.size();
|
||||
let h2_res = self.prepare_response(res.head(), &mut size);
|
||||
|
||||
let stream = send
|
||||
.send_response(h2_res, length.is_eof())
|
||||
.map_err(|e| {
|
||||
let stream =
|
||||
send.send_response(h2_res, size.is_eof()).map_err(|e| {
|
||||
trace!("Error sending h2 response: {:?}", e);
|
||||
})?;
|
||||
|
||||
if length.is_eof() {
|
||||
if size.is_eof() {
|
||||
Ok(Async::Ready(()))
|
||||
} else {
|
||||
self.state = ServiceResponseState::SendPayload(stream, body);
|
||||
|
@ -251,16 +250,15 @@ where
|
|||
let (res, body) = res.replace_body(());
|
||||
|
||||
let mut send = send.take().unwrap();
|
||||
let mut length = body.length();
|
||||
let h2_res = self.prepare_response(res.head(), &mut length);
|
||||
let mut size = body.size();
|
||||
let h2_res = self.prepare_response(res.head(), &mut size);
|
||||
|
||||
let stream = send
|
||||
.send_response(h2_res, length.is_eof())
|
||||
.map_err(|e| {
|
||||
let stream =
|
||||
send.send_response(h2_res, size.is_eof()).map_err(|e| {
|
||||
trace!("Error sending h2 response: {:?}", e);
|
||||
})?;
|
||||
|
||||
if length.is_eof() {
|
||||
if size.is_eof() {
|
||||
Ok(Async::Ready(()))
|
||||
} else {
|
||||
self.state = ServiceResponseState::SendPayload(
|
||||
|
|
|
@ -210,6 +210,18 @@ impl<B> Response<B> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Split response and body
|
||||
pub fn into_parts(self) -> (Response<()>, ResponseBody<B>) {
|
||||
(
|
||||
Response {
|
||||
head: self.head,
|
||||
body: ResponseBody::Body(()),
|
||||
error: self.error,
|
||||
},
|
||||
self.body,
|
||||
)
|
||||
}
|
||||
|
||||
/// Drop request's body
|
||||
pub fn drop_body(self) -> Response<()> {
|
||||
Response {
|
||||
|
@ -264,7 +276,7 @@ impl<B: MessageBody> fmt::Debug for Response<B> {
|
|||
for (key, val) in self.head.headers.iter() {
|
||||
let _ = writeln!(f, " {:?}: {:?}", key, val);
|
||||
}
|
||||
let _ = writeln!(f, " body: {:?}", self.body.length());
|
||||
let _ = writeln!(f, " body: {:?}", self.body.size());
|
||||
res
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ extern crate proc_macro;
|
|||
use std::fmt;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::{quote};
|
||||
use quote::quote;
|
||||
|
||||
enum ResourceType {
|
||||
Async,
|
||||
|
@ -51,9 +51,13 @@ impl fmt::Display for Args {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let ast = &self.ast;
|
||||
let guards = format!(".guard(actix_web::guard::{}())", self.guard);
|
||||
let guards = self.extra_guards.iter().fold(guards, |acc, val| format!("{}.guard(actix_web::guard::fn_guard({}))", acc, val));
|
||||
let guards = self.extra_guards.iter().fold(guards, |acc, val| {
|
||||
format!("{}.guard(actix_web::guard::fn_guard({}))", acc, val)
|
||||
});
|
||||
|
||||
write!(f, "
|
||||
write!(
|
||||
f,
|
||||
"
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct {name};
|
||||
|
||||
|
@ -65,7 +69,13 @@ impl<P: 'static> actix_web::dev::HttpServiceFactory<P> for {name} {{
|
|||
|
||||
actix_web::dev::HttpServiceFactory::register(resource, config)
|
||||
}}
|
||||
}}", name=self.name, ast=quote!(#ast), path=self.path, guards=guards, to=self.resource_type)
|
||||
}}",
|
||||
name = self.name,
|
||||
ast = quote!(#ast),
|
||||
path = self.path,
|
||||
guards = guards,
|
||||
to = self.resource_type
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,33 +83,41 @@ fn guess_resource_type(typ: &syn::Type) -> ResourceType {
|
|||
let mut guess = ResourceType::Sync;
|
||||
|
||||
match typ {
|
||||
syn::Type::ImplTrait(typ) => for bound in typ.bounds.iter() {
|
||||
match bound {
|
||||
syn::TypeParamBound::Trait(bound) => {
|
||||
for bound in bound.path.segments.iter() {
|
||||
if bound.ident == "Future" {
|
||||
guess = ResourceType::Async;
|
||||
break;
|
||||
} else if bound.ident == "Responder" {
|
||||
guess = ResourceType::Sync;
|
||||
break;
|
||||
syn::Type::ImplTrait(typ) => {
|
||||
for bound in typ.bounds.iter() {
|
||||
match bound {
|
||||
syn::TypeParamBound::Trait(bound) => {
|
||||
for bound in bound.path.segments.iter() {
|
||||
if bound.ident == "Future" {
|
||||
guess = ResourceType::Async;
|
||||
break;
|
||||
} else if bound.ident == "Responder" {
|
||||
guess = ResourceType::Sync;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
guess
|
||||
|
||||
}
|
||||
|
||||
impl Args {
|
||||
pub fn new(args: &Vec<syn::NestedMeta>, input: TokenStream, guard: GuardType) -> Self {
|
||||
pub fn new(
|
||||
args: &Vec<syn::NestedMeta>,
|
||||
input: TokenStream,
|
||||
guard: GuardType,
|
||||
) -> Self {
|
||||
if args.is_empty() {
|
||||
panic!("invalid server definition, expected: #[{}(\"some path\")]", guard);
|
||||
panic!(
|
||||
"invalid server definition, expected: #[{}(\"some path\")]",
|
||||
guard
|
||||
);
|
||||
}
|
||||
|
||||
let ast: syn::ItemFn = syn::parse(input).expect("Parse input as function");
|
||||
|
@ -115,15 +133,20 @@ impl Args {
|
|||
}
|
||||
let fname = quote!(#fname).to_string();
|
||||
path = Some(fname.as_str()[1..fname.len() - 1].to_owned())
|
||||
},
|
||||
syn::NestedMeta::Meta(syn::Meta::NameValue(ident)) => match ident.ident.to_string().to_lowercase().as_str() {
|
||||
"guard" => match ident.lit {
|
||||
syn::Lit::Str(ref text) => extra_guards.push(text.value()),
|
||||
_ => panic!("Attribute guard expects literal string!"),
|
||||
},
|
||||
attr => panic!("Unknown attribute key is specified: {}. Allowed: guard", attr)
|
||||
},
|
||||
attr => panic!("Unknown attribute{:?}", attr)
|
||||
}
|
||||
syn::NestedMeta::Meta(syn::Meta::NameValue(ident)) => {
|
||||
match ident.ident.to_string().to_lowercase().as_str() {
|
||||
"guard" => match ident.lit {
|
||||
syn::Lit::Str(ref text) => extra_guards.push(text.value()),
|
||||
_ => panic!("Attribute guard expects literal string!"),
|
||||
},
|
||||
attr => panic!(
|
||||
"Unknown attribute key is specified: {}. Allowed: guard",
|
||||
attr
|
||||
),
|
||||
}
|
||||
}
|
||||
attr => panic!("Unknown attribute{:?}", attr),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,7 +154,9 @@ impl Args {
|
|||
ResourceType::Async
|
||||
} else {
|
||||
match ast.decl.output {
|
||||
syn::ReturnType::Default => panic!("Function {} has no return type. Cannot be used as handler"),
|
||||
syn::ReturnType::Default => {
|
||||
panic!("Function {} has no return type. Cannot be used as handler")
|
||||
}
|
||||
syn::ReturnType::Type(_, ref typ) => guess_resource_type(typ.as_ref()),
|
||||
}
|
||||
};
|
||||
|
@ -153,7 +178,7 @@ impl Args {
|
|||
|
||||
match text.parse() {
|
||||
Ok(res) => res,
|
||||
Err(error) => panic!("Error: {:?}\nGenerated code: {}", error, text)
|
||||
Err(error) => panic!("Error: {:?}\nGenerated code: {}", error, text),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use actix_http::HttpService;
|
||||
use actix_http_test::TestServer;
|
||||
use actix_web_codegen::get;
|
||||
use actix_web::{http, App, HttpResponse, Responder};
|
||||
use futures::{Future, future};
|
||||
use actix_web_codegen::get;
|
||||
use futures::{future, Future};
|
||||
|
||||
//fn guard_head(head: &actix_web::dev::RequestHead) -> bool {
|
||||
// true
|
||||
|
@ -15,16 +15,15 @@ fn test() -> impl Responder {
|
|||
}
|
||||
|
||||
#[get("/test")]
|
||||
fn auto_async() -> impl Future<Item=HttpResponse, Error=actix_web::Error> {
|
||||
fn auto_async() -> impl Future<Item = HttpResponse, Error = actix_web::Error> {
|
||||
future::ok(HttpResponse::Ok().finish())
|
||||
}
|
||||
|
||||
#[get("/test")]
|
||||
fn auto_sync() -> impl Future<Item=HttpResponse, Error=actix_web::Error> {
|
||||
fn auto_sync() -> impl Future<Item = HttpResponse, Error = actix_web::Error> {
|
||||
future::ok(HttpResponse::Ok().finish())
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_body() {
|
||||
let mut srv = TestServer::new(|| HttpService::new(App::new().service(test)));
|
||||
|
|
|
@ -241,8 +241,8 @@ impl<B> Drop for StreamLog<B> {
|
|||
}
|
||||
|
||||
impl<B: MessageBody> MessageBody for StreamLog<B> {
|
||||
fn length(&self) -> BodySize {
|
||||
self.body.length()
|
||||
fn size(&self) -> BodySize {
|
||||
self.body.size()
|
||||
}
|
||||
|
||||
fn poll_next(&mut self) -> Poll<Option<Bytes>, Error> {
|
||||
|
|
|
@ -360,7 +360,7 @@ impl<B: MessageBody> fmt::Debug for ServiceResponse<B> {
|
|||
for (key, val) in self.response.head().headers.iter() {
|
||||
let _ = writeln!(f, " {:?}: {:?}", key, val);
|
||||
}
|
||||
let _ = writeln!(f, " body: {:?}", self.response.body().length());
|
||||
let _ = writeln!(f, " body: {:?}", self.response.body().size());
|
||||
res
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue