1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-07-01 16:55:08 +02:00

migrate actix-web to std::future

This commit is contained in:
Nikolay Kim
2019-11-20 23:33:22 +06:00
parent d081e57316
commit 3127dd4db6
46 changed files with 4134 additions and 3720 deletions

View File

@ -1,15 +1,18 @@
//! `Middleware` for compressing response body.
use std::cmp;
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::str::FromStr;
use std::task::{Context, Poll};
use actix_http::body::MessageBody;
use actix_http::encoding::Encoder;
use actix_http::http::header::{ContentEncoding, ACCEPT_ENCODING};
use actix_http::{Error, Response, ResponseBuilder};
use actix_service::{Service, Transform};
use futures::future::{ok, FutureResult};
use futures::{Async, Future, Poll};
use futures::future::{ok, Ready};
use pin_project::pin_project;
use crate::service::{ServiceRequest, ServiceResponse};
@ -78,7 +81,7 @@ where
type Error = Error;
type InitError = ();
type Transform = CompressMiddleware<S>;
type Future = FutureResult<Self::Transform, Self::InitError>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(CompressMiddleware {
@ -103,8 +106,8 @@ where
type Error = Error;
type Future = CompressResponse<S, B>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.service.poll_ready()
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, req: ServiceRequest) -> Self::Future {
@ -128,11 +131,13 @@ where
}
#[doc(hidden)]
#[pin_project]
pub struct CompressResponse<S, B>
where
S: Service,
B: MessageBody,
{
#[pin]
fut: S::Future,
encoding: ContentEncoding,
_t: PhantomData<(B)>,
@ -143,21 +148,25 @@ where
B: MessageBody,
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
{
type Item = ServiceResponse<Encoder<B>>;
type Error = Error;
type Output = Result<ServiceResponse<Encoder<B>>, Error>;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let resp = futures::try_ready!(self.fut.poll());
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = self.project();
let enc = if let Some(enc) = resp.response().extensions().get::<Enc>() {
enc.0
} else {
self.encoding
};
match futures::ready!(this.fut.poll(cx)) {
Ok(resp) => {
let enc = if let Some(enc) = resp.response().extensions().get::<Enc>() {
enc.0
} else {
*this.encoding
};
Ok(Async::Ready(resp.map_body(move |head, body| {
Encoder::response(enc, head, body)
})))
Poll::Ready(Ok(
resp.map_body(move |head, body| Encoder::response(enc, head, body))
))
}
Err(e) => Poll::Ready(Err(e)),
}
}
}

View File

@ -1,9 +1,11 @@
//! Middleware for setting default response headers
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll};
use actix_service::{Service, Transform};
use futures::future::{ok, FutureResult};
use futures::{Future, Poll};
use futures::future::{ok, FutureExt, LocalBoxFuture, Ready};
use crate::http::header::{HeaderName, HeaderValue, CONTENT_TYPE};
use crate::http::{HeaderMap, HttpTryFrom};
@ -96,7 +98,7 @@ where
type Error = Error;
type InitError = ();
type Transform = DefaultHeadersMiddleware<S>;
type Future = FutureResult<Self::Transform, Self::InitError>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(DefaultHeadersMiddleware {
@ -119,16 +121,19 @@ where
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type Future = Box<dyn Future<Item = Self::Response, Error = Self::Error>>;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.service.poll_ready()
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, req: ServiceRequest) -> Self::Future {
let inner = self.inner.clone();
let fut = self.service.call(req);
async move {
let mut res = fut.await?;
Box::new(self.service.call(req).map(move |mut res| {
// set response headers
for (key, value) in inner.headers.iter() {
if !res.headers().contains_key(key) {
@ -142,15 +147,16 @@ where
HeaderValue::from_static("application/octet-stream"),
);
}
res
}))
Ok(res)
}
.boxed_local()
}
}
#[cfg(test)]
mod tests {
use actix_service::IntoService;
use futures::future::ok;
use super::*;
use crate::dev::ServiceRequest;
@ -160,46 +166,50 @@ mod tests {
#[test]
fn test_default_headers() {
let mut mw = block_on(
DefaultHeaders::new()
block_on(async {
let mut mw = DefaultHeaders::new()
.header(CONTENT_TYPE, "0001")
.new_transform(ok_service()),
)
.unwrap();
.new_transform(ok_service())
.await
.unwrap();
let req = TestRequest::default().to_srv_request();
let resp = block_on(mw.call(req)).unwrap();
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001");
let req = TestRequest::default().to_srv_request();
let resp = mw.call(req).await.unwrap();
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001");
let req = TestRequest::default().to_srv_request();
let srv = |req: ServiceRequest| {
req.into_response(HttpResponse::Ok().header(CONTENT_TYPE, "0002").finish())
};
let mut mw = block_on(
DefaultHeaders::new()
let req = TestRequest::default().to_srv_request();
let srv = |req: ServiceRequest| {
ok(req.into_response(
HttpResponse::Ok().header(CONTENT_TYPE, "0002").finish(),
))
};
let mut mw = DefaultHeaders::new()
.header(CONTENT_TYPE, "0001")
.new_transform(srv.into_service()),
)
.unwrap();
let resp = block_on(mw.call(req)).unwrap();
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0002");
.new_transform(srv.into_service())
.await
.unwrap();
let resp = mw.call(req).await.unwrap();
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0002");
})
}
#[test]
fn test_content_type() {
let srv = |req: ServiceRequest| req.into_response(HttpResponse::Ok().finish());
let mut mw = block_on(
DefaultHeaders::new()
block_on(async {
let srv =
|req: ServiceRequest| ok(req.into_response(HttpResponse::Ok().finish()));
let mut mw = DefaultHeaders::new()
.content_type()
.new_transform(srv.into_service()),
)
.unwrap();
.new_transform(srv.into_service())
.await
.unwrap();
let req = TestRequest::default().to_srv_request();
let resp = block_on(mw.call(req)).unwrap();
assert_eq!(
resp.headers().get(CONTENT_TYPE).unwrap(),
"application/octet-stream"
);
let req = TestRequest::default().to_srv_request();
let resp = mw.call(req).await.unwrap();
assert_eq!(
resp.headers().get(CONTENT_TYPE).unwrap(),
"application/octet-stream"
);
})
}
}

View File

@ -2,13 +2,15 @@
use std::collections::HashSet;
use std::env;
use std::fmt::{self, Display, Formatter};
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll};
use actix_service::{Service, Transform};
use bytes::Bytes;
use futures::future::{ok, FutureResult};
use futures::{Async, Future, Poll};
use futures::future::{ok, Ready};
use log::debug;
use regex::Regex;
use time;
@ -125,7 +127,7 @@ where
type Error = Error;
type InitError = ();
type Transform = LoggerMiddleware<S>;
type Future = FutureResult<Self::Transform, Self::InitError>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(LoggerMiddleware {
@ -151,8 +153,8 @@ where
type Error = Error;
type Future = LoggerResponse<S, B>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.service.poll_ready()
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, req: ServiceRequest) -> Self::Future {
@ -181,11 +183,13 @@ where
}
#[doc(hidden)]
#[pin_project::pin_project]
pub struct LoggerResponse<S, B>
where
B: MessageBody,
S: Service,
{
#[pin]
fut: S::Future,
time: time::Tm,
format: Option<Format>,
@ -197,11 +201,15 @@ where
B: MessageBody,
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
{
type Item = ServiceResponse<StreamLog<B>>;
type Error = Error;
type Output = Result<ServiceResponse<StreamLog<B>>, Error>;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let res = futures::try_ready!(self.fut.poll());
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = self.project();
let res = match futures::ready!(this.fut.poll(cx)) {
Ok(res) => res,
Err(e) => return Poll::Ready(Err(e)),
};
if let Some(error) = res.response().error() {
if res.response().head().status != StatusCode::INTERNAL_SERVER_ERROR {
@ -209,18 +217,21 @@ where
}
}
if let Some(ref mut format) = self.format {
if let Some(ref mut format) = this.format {
for unit in &mut format.0 {
unit.render_response(res.response());
}
}
Ok(Async::Ready(res.map_body(move |_, body| {
let time = *this.time;
let format = this.format.take();
Poll::Ready(Ok(res.map_body(move |_, body| {
ResponseBody::Body(StreamLog {
body,
time,
format,
size: 0,
time: self.time,
format: self.format.take(),
})
})))
}
@ -252,13 +263,13 @@ impl<B: MessageBody> MessageBody for StreamLog<B> {
self.body.size()
}
fn poll_next(&mut self) -> Poll<Option<Bytes>, Error> {
match self.body.poll_next()? {
Async::Ready(Some(chunk)) => {
fn poll_next(&mut self, cx: &mut Context) -> Poll<Option<Result<Bytes, Error>>> {
match self.body.poll_next(cx) {
Poll::Ready(Some(Ok(chunk))) => {
self.size += chunk.len();
Ok(Async::Ready(Some(chunk)))
Poll::Ready(Some(Ok(chunk)))
}
val => Ok(val),
val => val,
}
}
}
@ -464,6 +475,7 @@ impl<'a> fmt::Display for FormatDisplay<'a> {
#[cfg(test)]
mod tests {
use actix_service::{IntoService, Service, Transform};
use futures::future::ok;
use super::*;
use crate::http::{header, StatusCode};
@ -472,11 +484,11 @@ mod tests {
#[test]
fn test_logger() {
let srv = |req: ServiceRequest| {
req.into_response(
ok(req.into_response(
HttpResponse::build(StatusCode::OK)
.header("X-Test", "ttt")
.finish(),
)
))
};
let logger = Logger::new("%% %{User-Agent}i %{X-Test}o %{HOME}e %D test");

View File

@ -2,13 +2,13 @@
mod compress;
pub use self::compress::{BodyEncoding, Compress};
mod condition;
//mod condition;
mod defaultheaders;
pub mod errhandlers;
//pub mod errhandlers;
mod logger;
mod normalize;
//mod normalize;
pub use self::condition::Condition;
//pub use self::condition::Condition;
pub use self::defaultheaders::DefaultHeaders;
pub use self::logger::Logger;
pub use self::normalize::NormalizePath;
//pub use self::normalize::NormalizePath;