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:
@ -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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user