1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-11-25 11:01:14 +00:00

rename .to_async() to .to()

This commit is contained in:
Nikolay Kim 2019-11-21 21:34:04 +06:00
parent 0b9e3d381b
commit 8683ba8bb0
25 changed files with 232 additions and 396 deletions

View file

@ -74,7 +74,7 @@ actix-service = "1.0.0-alpha.1"
actix-utils = "0.5.0-alpha.1"
actix-router = "0.1.5"
actix-rt = "1.0.0-alpha.1"
actix-web-codegen = "0.1.2"
actix-web-codegen = "0.2.0-alpha.1"
actix-http = "0.3.0-alpha.1"
actix-server = "0.8.0-alpha.1"
actix-server-config = "0.3.0-alpha.1"

View file

@ -1,3 +1,10 @@
## 2.0.0
* Sync handlers has been removed. `.to_async()` methtod has been renamed to `.to()`
replace `fn` with `async fn` to convert sync handler to async
## 1.0.1
* Cors middleware has been moved to `actix-cors` crate

View file

@ -29,7 +29,7 @@ Actix web is a simple, pragmatic and extremely fast web framework for Rust.
```rust
use actix_web::{web, App, HttpServer, Responder};
fn index(info: web::Path<(u32, String)>) -> impl Responder {
async fn index(info: web::Path<(u32, String)>) -> impl Responder {
format!("Hello {}! id:{}", info.1, info.0)
}

View file

@ -1,11 +1,14 @@
//! Http response
use std::cell::{Ref, RefMut};
use std::future::Future;
use std::io::Write;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::{fmt, str};
use bytes::{BufMut, Bytes, BytesMut};
use futures::future::{ok, Ready};
use futures::Stream;
use futures::stream::Stream;
use serde::Serialize;
use serde_json;
@ -280,15 +283,20 @@ impl<B: MessageBody> fmt::Debug for Response<B> {
}
}
// impl IntoFuture for Response {
// type Item = Response;
// type Error = Error;
// type Future = FutureResult<Response, Error>;
impl Future for Response {
type Output = Result<Response, Error>;
// fn into_future(self) -> Self::Future {
// ok(self)
// }
// }
fn poll(mut self: Pin<&mut Self>, _: &mut Context) -> Poll<Self::Output> {
Poll::Ready(Ok(Response {
head: std::mem::replace(
&mut self.head,
BoxedResponseHead::new(StatusCode::OK),
),
body: self.body.take_body(),
error: self.error.take(),
}))
}
}
pub struct CookieIter<'a> {
iter: header::GetAll<'a>,
@ -757,15 +765,13 @@ impl<'a> From<&'a ResponseHead> for ResponseBuilder {
}
}
// impl IntoFuture for ResponseBuilder {
// type Item = Response;
// type Error = Error;
// type Future = FutureResult<Response, Error>;
impl Future for ResponseBuilder {
type Output = Result<Response, Error>;
// fn into_future(mut self) -> Self::Future {
// ok(self.finish())
// }
// }
fn poll(mut self: Pin<&mut Self>, _: &mut Context) -> Poll<Self::Output> {
Poll::Ready(Ok(self.finish()))
}
}
impl fmt::Debug for ResponseBuilder {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

View file

@ -13,7 +13,7 @@ enum ResourceType {
impl ToTokens for ResourceType {
fn to_tokens(&self, stream: &mut TokenStream2) {
let ident = match self {
ResourceType::Async => "to_async",
ResourceType::Async => "to",
ResourceType::Sync => "to",
};
let ident = Ident::new(ident, Span::call_site());

View file

@ -1,9 +1,7 @@
use actix_web::{
get, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer,
};
use actix_web::{get, middleware, web, App, HttpRequest, HttpResponse, HttpServer};
#[get("/resource1/{name}/index.html")]
fn index(req: HttpRequest, name: web::Path<String>) -> String {
async fn index(req: HttpRequest, name: web::Path<String>) -> String {
println!("REQ: {:?}", req);
format!("Hello: {}!\r\n", name)
}
@ -14,7 +12,7 @@ async fn index_async(req: HttpRequest) -> &'static str {
}
#[get("/")]
fn no_params() -> &'static str {
async fn no_params() -> &'static str {
"Hello world!\r\n"
}
@ -37,9 +35,9 @@ fn main() -> std::io::Result<()> {
.default_service(
web::route().to(|| HttpResponse::MethodNotAllowed()),
)
.route(web::get().to_async(index_async)),
.route(web::get().to(index_async)),
)
.service(web::resource("/test1.html").to(|| "Test\r\n"))
.service(web::resource("/test1.html").to(|| async { "Test\r\n" }))
})
.bind("127.0.0.1:8080")?
.workers(1)

View file

@ -3,7 +3,7 @@ use actix_web::{
};
#[get("/resource1/{name}/index.html")]
fn index(req: HttpRequest, name: web::Path<String>) -> String {
async fn index(req: HttpRequest, name: web::Path<String>) -> String {
println!("REQ: {:?}", req);
format!("Hello: {}!\r\n", name)
}
@ -14,11 +14,11 @@ async fn index_async(req: HttpRequest) -> Result<&'static str, Error> {
}
#[get("/")]
fn no_params() -> &'static str {
async fn no_params() -> &'static str {
"Hello world!\r\n"
}
#[cfg(feature = "uds")]
#[cfg(unix)]
fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "actix_server=info,actix_web=info");
env_logger::init();
@ -27,7 +27,7 @@ fn main() -> std::io::Result<()> {
App::new()
.wrap(middleware::DefaultHeaders::new().header("X-Version", "0.2"))
.wrap(middleware::Compress::default())
// .wrap(middleware::Logger::default())
.wrap(middleware::Logger::default())
.service(index)
.service(no_params)
.service(
@ -36,16 +36,16 @@ fn main() -> std::io::Result<()> {
middleware::DefaultHeaders::new().header("X-Version-R2", "0.3"),
)
.default_service(
web::route().to(|| ok(HttpResponse::MethodNotAllowed())),
web::route().to(|| HttpResponse::MethodNotAllowed()),
)
.route(web::get().to_async(index_async)),
.route(web::get().to(index_async)),
)
.service(web::resource("/test1.html").to(|| "Test\r\n"))
.service(web::resource("/test1.html").to(|| async { "Test\r\n" }))
})
.bind_uds("/Users/fafhrd91/uds-test")?
.workers(1)
.run()
}
#[cfg(not(feature = "uds"))]
#[cfg(not(unix))]
fn main() {}

View file

@ -90,7 +90,7 @@ where
/// counter: Cell<usize>,
/// }
///
/// fn index(data: web::Data<MyData>) {
/// async fn index(data: web::Data<MyData>) {
/// data.counter.set(data.counter.get() + 1);
/// }
///
@ -192,7 +192,7 @@ where
/// ```rust
/// use actix_web::{web, App, HttpResponse};
///
/// fn index(data: web::Path<(String, String)>) -> &'static str {
/// async fn index(data: web::Path<(String, String)>) -> &'static str {
/// "Welcome!"
/// }
///
@ -247,7 +247,7 @@ where
/// ```rust
/// use actix_web::{web, App, HttpResponse};
///
/// fn index() -> &'static str {
/// async fn index() -> &'static str {
/// "Welcome!"
/// }
///
@ -302,7 +302,7 @@ where
/// ```rust
/// use actix_web::{web, App, HttpRequest, HttpResponse, Result};
///
/// fn index(req: HttpRequest) -> Result<HttpResponse> {
/// async fn index(req: HttpRequest) -> Result<HttpResponse> {
/// let url = req.url_for("youtube", &["asdlkjqme"])?;
/// assert_eq!(url.as_str(), "https://youtube.com/watch/asdlkjqme");
/// Ok(HttpResponse::Ok().into())
@ -346,7 +346,7 @@ where
/// use actix_web::{middleware, web, App};
/// use actix_web::http::{header::CONTENT_TYPE, HeaderValue};
///
/// fn index() -> &'static str {
/// async fn index() -> &'static str {
/// "Welcome!"
/// }
///
@ -404,7 +404,7 @@ where
/// use actix_web::{web, App};
/// use actix_web::http::{header::CONTENT_TYPE, HeaderValue};
///
/// fn index() -> &'static str {
/// async fn index() -> &'static str {
/// "Welcome!"
/// }
///

View file

@ -45,7 +45,7 @@ pub(crate) trait DataFactory {
/// }
///
/// /// Use `Data<T>` extractor to access data in handler.
/// fn index(data: web::Data<Mutex<MyData>>) {
/// async fn index(data: web::Data<Mutex<MyData>>) {
/// let mut data = data.lock().unwrap();
/// data.counter += 1;
/// }

View file

@ -75,7 +75,7 @@ pub trait FromRequest: Sized {
/// }
///
/// /// extract `Thing` from request
/// fn index(supplied_thing: Option<Thing>) -> String {
/// async fn index(supplied_thing: Option<Thing>) -> String {
/// match supplied_thing {
/// // Puns not intended
/// Some(thing) => format!("Got something: {:?}", thing),
@ -146,7 +146,7 @@ where
/// }
///
/// /// extract `Thing` from request
/// fn index(supplied_thing: Result<Thing>) -> String {
/// async fn index(supplied_thing: Result<Thing>) -> String {
/// match supplied_thing {
/// Ok(thing) => format!("Got thing: {:?}", thing),
/// Err(e) => format!("Error extracting thing: {}", e)

View file

@ -15,111 +15,8 @@ use crate::request::HttpRequest;
use crate::responder::Responder;
use crate::service::{ServiceRequest, ServiceResponse};
/// Handler converter factory
pub trait Factory<T, R>: Clone
where
R: Responder,
{
fn call(&self, param: T) -> R;
}
impl<F, R> Factory<(), R> for F
where
F: Fn() -> R + Clone,
R: Responder,
{
fn call(&self, _: ()) -> R {
(self)()
}
}
#[doc(hidden)]
pub struct Handler<F, T, R>
where
F: Factory<T, R>,
R: Responder,
{
hnd: F,
_t: PhantomData<(T, R)>,
}
impl<F, T, R> Handler<F, T, R>
where
F: Factory<T, R>,
R: Responder,
{
pub fn new(hnd: F) -> Self {
Handler {
hnd,
_t: PhantomData,
}
}
}
impl<F, T, R> Clone for Handler<F, T, R>
where
F: Factory<T, R>,
R: Responder,
{
fn clone(&self) -> Self {
Self {
hnd: self.hnd.clone(),
_t: PhantomData,
}
}
}
impl<F, T, R> Service for Handler<F, T, R>
where
F: Factory<T, R>,
R: Responder,
{
type Request = (T, HttpRequest);
type Response = ServiceResponse;
type Error = Infallible;
type Future = HandlerServiceResponse<R>;
fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, (param, req): (T, HttpRequest)) -> Self::Future {
let fut = self.hnd.call(param).respond_to(&req);
HandlerServiceResponse {
fut,
req: Some(req),
}
}
}
#[pin_project]
pub struct HandlerServiceResponse<T: Responder> {
#[pin]
fut: T::Future,
req: Option<HttpRequest>,
}
impl<T: Responder> Future for HandlerServiceResponse<T> {
type Output = Result<ServiceResponse, Infallible>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = self.project();
match this.fut.poll(cx) {
Poll::Ready(Ok(res)) => {
Poll::Ready(Ok(ServiceResponse::new(this.req.take().unwrap(), res)))
}
Poll::Pending => Poll::Pending,
Poll::Ready(Err(e)) => {
let res: Response = e.into().into();
Poll::Ready(Ok(ServiceResponse::new(this.req.take().unwrap(), res)))
}
}
}
}
/// Async handler converter factory
pub trait AsyncFactory<T, R, O>: Clone + 'static
pub trait Factory<T, R, O>: Clone + 'static
where
R: Future<Output = O>,
O: Responder,
@ -127,7 +24,7 @@ where
fn call(&self, param: T) -> R;
}
impl<F, R, O> AsyncFactory<(), R, O> for F
impl<F, R, O> Factory<(), R, O> for F
where
F: Fn() -> R + Clone + 'static,
R: Future<Output = O>,
@ -139,9 +36,9 @@ where
}
#[doc(hidden)]
pub struct AsyncHandler<F, T, R, O>
pub struct Handler<F, T, R, O>
where
F: AsyncFactory<T, R, O>,
F: Factory<T, R, O>,
R: Future<Output = O>,
O: Responder,
{
@ -149,51 +46,51 @@ where
_t: PhantomData<(T, R, O)>,
}
impl<F, T, R, O> AsyncHandler<F, T, R, O>
impl<F, T, R, O> Handler<F, T, R, O>
where
F: AsyncFactory<T, R, O>,
F: Factory<T, R, O>,
R: Future<Output = O>,
O: Responder,
{
pub fn new(hnd: F) -> Self {
AsyncHandler {
Handler {
hnd,
_t: PhantomData,
}
}
}
impl<F, T, R, O> Clone for AsyncHandler<F, T, R, O>
impl<F, T, R, O> Clone for Handler<F, T, R, O>
where
F: AsyncFactory<T, R, O>,
F: Factory<T, R, O>,
R: Future<Output = O>,
O: Responder,
{
fn clone(&self) -> Self {
AsyncHandler {
Handler {
hnd: self.hnd.clone(),
_t: PhantomData,
}
}
}
impl<F, T, R, O> Service for AsyncHandler<F, T, R, O>
impl<F, T, R, O> Service for Handler<F, T, R, O>
where
F: AsyncFactory<T, R, O>,
F: Factory<T, R, O>,
R: Future<Output = O>,
O: Responder,
{
type Request = (T, HttpRequest);
type Response = ServiceResponse;
type Error = Infallible;
type Future = AsyncHandlerServiceResponse<R, O>;
type Future = HandlerServiceResponse<R, O>;
fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, (param, req): (T, HttpRequest)) -> Self::Future {
AsyncHandlerServiceResponse {
HandlerServiceResponse {
fut: self.hnd.call(param),
fut2: None,
req: Some(req),
@ -203,7 +100,7 @@ where
#[doc(hidden)]
#[pin_project]
pub struct AsyncHandlerServiceResponse<T, R>
pub struct HandlerServiceResponse<T, R>
where
T: Future<Output = R>,
R: Responder,
@ -215,7 +112,7 @@ where
req: Option<HttpRequest>,
}
impl<T, R> Future for AsyncHandlerServiceResponse<T, R>
impl<T, R> Future for HandlerServiceResponse<T, R>
where
T: Future<Output = R>,
R: Responder,
@ -366,16 +263,7 @@ where
/// FromRequest trait impl for tuples
macro_rules! factory_tuple ({ $(($n:tt, $T:ident)),+} => {
impl<Func, $($T,)+ Res> Factory<($($T,)+), Res> for Func
where Func: Fn($($T,)+) -> Res + Clone,
Res: Responder,
{
fn call(&self, param: ($($T,)+)) -> Res {
(self)($(param.$n,)+)
}
}
impl<Func, $($T,)+ Res, O> AsyncFactory<($($T,)+), Res, O> for Func
impl<Func, $($T,)+ Res, O> Factory<($($T,)+), Res, O> for Func
where Func: Fn($($T,)+) -> Res + Clone + 'static,
Res: Future<Output = O>,
O: Responder,

View file

@ -6,7 +6,7 @@
//! use actix_web::{web, App, Responder, HttpServer};
//! # use std::thread;
//!
//! fn index(info: web::Path<(String, u32)>) -> impl Responder {
//! async fn index(info: web::Path<(String, u32)>) -> impl Responder {
//! format!("Hello {}! id:{}", info.0, info.1)
//! }
//!
@ -136,7 +136,7 @@ pub mod dev {
pub use crate::config::{AppConfig, AppService};
#[doc(hidden)]
pub use crate::handler::{AsyncFactory, Factory};
pub use crate::handler::Factory;
pub use crate::info::ConnectionInfo;
pub use crate::rmap::ResourceMap;
pub use crate::service::{

View file

@ -276,7 +276,7 @@ impl Drop for HttpRequest {
/// use serde_derive::Deserialize;
///
/// /// extract `Thing` from request
/// fn index(req: HttpRequest) -> String {
/// async fn index(req: HttpRequest) -> String {
/// format!("Got thing: {:?}", req)
/// }
///

View file

@ -17,7 +17,7 @@ use crate::data::Data;
use crate::dev::{insert_slash, AppService, HttpServiceFactory, ResourceDef};
use crate::extract::FromRequest;
use crate::guard::Guard;
use crate::handler::{AsyncFactory, Factory};
use crate::handler::Factory;
use crate::responder::Responder;
use crate::route::{CreateRouteService, Route, RouteService};
use crate::service::{ServiceRequest, ServiceResponse};
@ -98,7 +98,7 @@ where
/// ```rust
/// use actix_web::{web, guard, App, HttpResponse};
///
/// fn index(data: web::Path<(String, String)>) -> &'static str {
/// async fn index(data: web::Path<(String, String)>) -> &'static str {
/// "Welcome!"
/// }
///
@ -156,9 +156,9 @@ where
/// .route(web::delete().to(delete_handler))
/// );
/// }
/// # fn get_handler() {}
/// # fn post_handler() {}
/// # fn delete_handler() {}
/// # async fn get_handler() -> impl actix_web::Responder { HttpResponse::Ok() }
/// # async fn post_handler() -> impl actix_web::Responder { HttpResponse::Ok() }
/// # async fn delete_handler() -> impl actix_web::Responder { HttpResponse::Ok() }
/// ```
pub fn route(mut self, route: Route) -> Self {
self.routes.push(route);
@ -174,7 +174,7 @@ where
/// use actix_web::{web, App, FromRequest};
///
/// /// extract text data from request
/// fn index(body: String) -> String {
/// async fn index(body: String) -> String {
/// format!("Body {}!", body)
/// }
///
@ -230,46 +230,14 @@ where
/// # fn index(req: HttpRequest) -> HttpResponse { unimplemented!() }
/// App::new().service(web::resource("/").route(web::route().to(index)));
/// ```
pub fn to<F, I, R>(mut self, handler: F) -> Self
pub fn to<F, I, R, U>(mut self, handler: F) -> Self
where
F: Factory<I, R> + 'static,
I: FromRequest + 'static,
R: Responder + 'static,
{
self.routes.push(Route::new().to(handler));
self
}
/// Register a new route and add async handler.
///
/// ```rust
/// use actix_web::*;
///
/// async fn index(req: HttpRequest) -> Result<HttpResponse, Error> {
/// Ok(HttpResponse::Ok().finish())
/// }
///
/// App::new().service(web::resource("/").to_async(index));
/// ```
///
/// This is shortcut for:
///
/// ```rust
/// # use actix_web::*;
/// # async fn index(req: HttpRequest) -> Result<HttpResponse, Error> {
/// # unimplemented!()
/// # }
/// App::new().service(web::resource("/").route(web::route().to_async(index)));
/// ```
#[allow(clippy::wrong_self_convention)]
pub fn to_async<F, I, R, U>(mut self, handler: F) -> Self
where
F: AsyncFactory<I, R, U>,
F: Factory<I, R, U>,
I: FromRequest + 'static,
R: Future<Output = U> + 'static,
U: Responder + 'static,
{
self.routes.push(Route::new().to_async(handler));
self.routes.push(Route::new().to(handler));
self
}
@ -327,7 +295,7 @@ where
/// use actix_web::{web, App};
/// use actix_web::http::{header::CONTENT_TYPE, HeaderValue};
///
/// fn index() -> &'static str {
/// async fn index() -> &'static str {
/// "Welcome!"
/// }
///
@ -705,17 +673,16 @@ mod tests {
}
#[test]
fn test_to_async() {
fn test_to() {
block_on(async {
let mut srv = init_service(App::new().service(
web::resource("/test").to_async(|| {
let mut srv =
init_service(App::new().service(web::resource("/test").to(|| {
async {
delay_for(Duration::from_millis(100)).await;
Ok::<_, Error>(HttpResponse::Ok())
}
}),
))
.await;
})))
.await;
let req = TestRequest::with_uri("/test").to_request();
let resp = call_service(&mut srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);

View file

@ -475,9 +475,10 @@ pub(crate) mod tests {
let mut srv = init_service(
App::new()
.service(
web::resource("/none").to(|| -> Option<&'static str> { None }),
web::resource("/none")
.to(|| async { Option::<&'static str>::None }),
)
.service(web::resource("/some").to(|| Some("some"))),
.service(web::resource("/some").to(|| async { Some("some") })),
)
.await;

View file

@ -5,11 +5,11 @@ use std::task::{Context, Poll};
use actix_http::{http::Method, Error};
use actix_service::{Service, ServiceFactory};
use futures::future::{ok, Either, FutureExt, LocalBoxFuture, Ready};
use futures::future::{ok, ready, Either, FutureExt, LocalBoxFuture, Ready};
use crate::extract::FromRequest;
use crate::guard::{self, Guard};
use crate::handler::{AsyncFactory, AsyncHandler, Extract, Factory, Handler};
use crate::handler::{Extract, Factory, Handler};
use crate::responder::Responder;
use crate::service::{ServiceRequest, ServiceResponse};
use crate::HttpResponse;
@ -49,7 +49,7 @@ impl Route {
pub fn new() -> Route {
Route {
service: Box::new(RouteNewService::new(Extract::new(Handler::new(|| {
HttpResponse::NotFound()
ready(HttpResponse::NotFound())
})))),
guards: Rc::new(Vec::new()),
}
@ -187,7 +187,7 @@ impl Route {
/// }
///
/// /// extract path info using serde
/// fn index(info: web::Path<Info>) -> String {
/// async fn index(info: web::Path<Info>) -> String {
/// format!("Welcome {}!", info.username)
/// }
///
@ -212,7 +212,7 @@ impl Route {
/// }
///
/// /// extract path info using serde
/// fn index(path: web::Path<Info>, query: web::Query<HashMap<String, String>>, body: web::Json<Info>) -> String {
/// async fn index(path: web::Path<Info>, query: web::Query<HashMap<String, String>>, body: web::Json<Info>) -> String {
/// format!("Welcome {}!", path.username)
/// }
///
@ -223,52 +223,15 @@ impl Route {
/// );
/// }
/// ```
pub fn to<F, T, R>(mut self, handler: F) -> Route
pub fn to<F, T, R, U>(mut self, handler: F) -> Self
where
F: Factory<T, R> + 'static,
T: FromRequest + 'static,
R: Responder + 'static,
{
self.service =
Box::new(RouteNewService::new(Extract::new(Handler::new(handler))));
self
}
/// Set async handler function, use request extractors for parameters.
/// This method has to be used if your handler function returns `impl Future<>`
///
/// ```rust
/// use actix_web::{web, App, Error};
/// use serde_derive::Deserialize;
///
/// #[derive(Deserialize)]
/// struct Info {
/// username: String,
/// }
///
/// /// extract path info using serde
/// async fn index(info: web::Path<Info>) -> Result<&'static str, Error> {
/// Ok("Hello World!")
/// }
///
/// fn main() {
/// let app = App::new().service(
/// web::resource("/{username}/index.html") // <- define path parameters
/// .route(web::get().to_async(index)) // <- register async handler
/// );
/// }
/// ```
#[allow(clippy::wrong_self_convention)]
pub fn to_async<F, T, R, U>(mut self, handler: F) -> Self
where
F: AsyncFactory<T, R, U>,
F: Factory<T, R, U>,
T: FromRequest + 'static,
R: Future<Output = U> + 'static,
U: Responder + 'static,
{
self.service = Box::new(RouteNewService::new(Extract::new(AsyncHandler::new(
handler,
))));
self.service =
Box::new(RouteNewService::new(Extract::new(Handler::new(handler))));
self
}
}
@ -402,22 +365,24 @@ mod tests {
web::resource("/test")
.route(web::get().to(|| HttpResponse::Ok()))
.route(web::put().to(|| {
Err::<HttpResponse, _>(error::ErrorBadRequest("err"))
async {
Err::<HttpResponse, _>(error::ErrorBadRequest("err"))
}
}))
.route(web::post().to_async(|| {
.route(web::post().to(|| {
async {
delay_for(Duration::from_millis(100)).await;
HttpResponse::Created()
}
}))
.route(web::delete().to_async(|| {
.route(web::delete().to(|| {
async {
delay_for(Duration::from_millis(100)).await;
Err::<HttpResponse, _>(error::ErrorBadRequest("err"))
}
})),
)
.service(web::resource("/json").route(web::get().to_async(|| {
.service(web::resource("/json").route(web::get().to(|| {
async {
delay_for(Duration::from_millis(25)).await;
web::Json(MyObject {

View file

@ -46,7 +46,7 @@ type BoxedResponse = LocalBoxFuture<'static, Result<ServiceResponse, Error>>;
/// fn main() {
/// let app = App::new().service(
/// web::scope("/{project_id}/")
/// .service(web::resource("/path1").to(|| HttpResponse::Ok()))
/// .service(web::resource("/path1").to(|| async { HttpResponse::Ok() }))
/// .service(web::resource("/path2").route(web::get().to(|| HttpResponse::Ok())))
/// .service(web::resource("/path3").route(web::head().to(|| HttpResponse::MethodNotAllowed())))
/// );
@ -101,7 +101,7 @@ where
/// ```rust
/// use actix_web::{web, guard, App, HttpRequest, HttpResponse};
///
/// fn index(data: web::Path<(String, String)>) -> &'static str {
/// async fn index(data: web::Path<(String, String)>) -> &'static str {
/// "Welcome!"
/// }
///
@ -132,7 +132,7 @@ where
/// counter: Cell<usize>,
/// }
///
/// fn index(data: web::Data<MyData>) {
/// async fn index(data: web::Data<MyData>) {
/// data.counter.set(data.counter.get() + 1);
/// }
///
@ -228,7 +228,7 @@ where
///
/// struct AppState;
///
/// fn index(req: HttpRequest) -> &'static str {
/// async fn index(req: HttpRequest) -> &'static str {
/// "Welcome!"
/// }
///
@ -258,7 +258,7 @@ where
/// ```rust
/// use actix_web::{web, App, HttpResponse};
///
/// fn index(data: web::Path<(String, String)>) -> &'static str {
/// async fn index(data: web::Path<(String, String)>) -> &'static str {
/// "Welcome!"
/// }
///
@ -356,7 +356,7 @@ where
/// use actix_web::{web, App};
/// use actix_web::http::{header::CONTENT_TYPE, HeaderValue};
///
/// fn index() -> &'static str {
/// async fn index() -> &'static str {
/// "Welcome!"
/// }
///
@ -846,8 +846,10 @@ mod tests {
let mut srv =
init_service(App::new().service(web::scope("/ab-{project}").service(
web::resource("/path1").to(|r: HttpRequest| {
HttpResponse::Ok()
.body(format!("project: {}", &r.match_info()["project"]))
async move {
HttpResponse::Ok()
.body(format!("project: {}", &r.match_info()["project"]))
}
}),
)))
.await;
@ -962,8 +964,12 @@ mod tests {
let mut srv = init_service(App::new().service(web::scope("/app").service(
web::scope("/{project_id}").service(web::resource("/path1").to(
|r: HttpRequest| {
HttpResponse::Created()
.body(format!("project: {}", &r.match_info()["project_id"]))
async move {
HttpResponse::Created().body(format!(
"project: {}",
&r.match_info()["project_id"]
))
}
},
)),
)))
@ -989,11 +995,13 @@ mod tests {
let mut srv = init_service(App::new().service(web::scope("/app").service(
web::scope("/{project}").service(web::scope("/{id}").service(
web::resource("/path1").to(|r: HttpRequest| {
HttpResponse::Created().body(format!(
"project: {} - {}",
&r.match_info()["project"],
&r.match_info()["id"],
))
async move {
HttpResponse::Created().body(format!(
"project: {} - {}",
&r.match_info()["project"],
&r.match_info()["id"],
))
}
}),
)),
)))
@ -1241,12 +1249,14 @@ mod tests {
s.route(
"/",
web::get().to(|req: HttpRequest| {
HttpResponse::Ok().body(format!(
"{}",
req.url_for("youtube", &["xxxxxx"])
.unwrap()
.as_str()
))
async move {
HttpResponse::Ok().body(format!(
"{}",
req.url_for("youtube", &["xxxxxx"])
.unwrap()
.as_str()
))
}
}),
);
}));
@ -1267,8 +1277,12 @@ mod tests {
let mut srv = init_service(App::new().service(web::scope("/a").service(
web::scope("/b").service(web::resource("/c/{stuff}").name("c").route(
web::get().to(|req: HttpRequest| {
HttpResponse::Ok()
.body(format!("{}", req.url_for("c", &["12345"]).unwrap()))
async move {
HttpResponse::Ok().body(format!(
"{}",
req.url_for("c", &["12345"]).unwrap()
))
}
}),
)),
)))

View file

@ -55,7 +55,7 @@ pub fn default_service(
/// fn test_init_service() {
/// let mut app = test::init_service(
/// App::new()
/// .service(web::resource("/test").to(|| HttpResponse::Ok()))
/// .service(web::resource("/test").to(|| async { HttpResponse::Ok() }))
/// );
///
/// // Create request object
@ -94,14 +94,16 @@ where
/// fn test_response() {
/// let mut app = test::init_service(
/// App::new()
/// .service(web::resource("/test").to(|| HttpResponse::Ok()))
/// );
/// .service(web::resource("/test").to(|| async {
/// HttpResponse::Ok()
/// }))
/// ).await;
///
/// // Create request object
/// let req = test::TestRequest::with_uri("/test").to_request();
///
/// // Call application
/// let resp = test::call_service(&mut app, req);
/// let resp = test::call_service(&mut app, req).await;
/// assert_eq!(resp.status(), StatusCode::OK);
/// }
/// ```
@ -125,15 +127,17 @@ where
/// let mut app = test::init_service(
/// App::new().service(
/// web::resource("/index.html")
/// .route(web::post().to(
/// || HttpResponse::Ok().body("welcome!")))));
/// .route(web::post().to(|| async {
/// HttpResponse::Ok().body("welcome!")
/// })))
/// ).await;
///
/// let req = test::TestRequest::post()
/// .uri("/index.html")
/// .header(header::CONTENT_TYPE, "application/json")
/// .to_request();
///
/// let result = test::read_response(&mut app, req);
/// let result = test::read_response(&mut app, req).await;
/// assert_eq!(result, Bytes::from_static(b"welcome!"));
/// }
/// ```
@ -167,15 +171,17 @@ where
/// let mut app = test::init_service(
/// App::new().service(
/// web::resource("/index.html")
/// .route(web::post().to(
/// || HttpResponse::Ok().body("welcome!")))));
/// .route(web::post().to(|| async {
/// HttpResponse::Ok().body("welcome!")
/// })))
/// ).await;
///
/// let req = test::TestRequest::post()
/// .uri("/index.html")
/// .header(header::CONTENT_TYPE, "application/json")
/// .to_request();
///
/// let resp = test::call_service(&mut app, req);
/// let resp = test::call_service(&mut app, req).await;
/// let result = test::read_body(resp);
/// assert_eq!(result, Bytes::from_static(b"welcome!"));
/// }
@ -221,10 +227,11 @@ where
/// let mut app = test::init_service(
/// App::new().service(
/// web::resource("/people")
/// .route(web::post().to(|person: web::Json<Person>| {
/// .route(web::post().to(|person: web::Json<Person>| async {
/// HttpResponse::Ok()
/// .json(person.into_inner())})
/// )));
/// ))
/// ).await;
///
/// let payload = r#"{"id":"12345","name":"User name"}"#.as_bytes();
///
@ -234,7 +241,7 @@ where
/// .set_payload(payload)
/// .to_request();
///
/// let result: Person = test::read_response_json(&mut app, req);
/// let result: Person = test::read_response_json(&mut app, req).await;
/// }
/// ```
pub async fn read_response_json<S, B, T>(app: &mut S, req: Request) -> T
@ -262,7 +269,7 @@ where
/// use actix_web::{test, HttpRequest, HttpResponse, HttpMessage};
/// use actix_web::http::{header, StatusCode};
///
/// fn index(req: HttpRequest) -> HttpResponse {
/// async fn index(req: HttpRequest) -> HttpResponse {
/// if let Some(hdr) = req.headers().get(header::CONTENT_TYPE) {
/// HttpResponse::Ok().into()
/// } else {
@ -275,11 +282,11 @@ where
/// let req = test::TestRequest::with_header("content-type", "text/plain")
/// .to_http_request();
///
/// let resp = test::block_on(index(req)).unwrap();
/// let resp = index(req).await.unwrap();
/// assert_eq!(resp.status(), StatusCode::OK);
///
/// let req = test::TestRequest::default().to_http_request();
/// let resp = test::block_on(index(req)).unwrap();
/// let resp = index(req).await.unwrap();
/// assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
/// }
/// ```
@ -535,9 +542,17 @@ mod tests {
let mut app = init_service(
App::new().service(
web::resource("/index.html")
.route(web::put().to(|| HttpResponse::Ok().body("put!")))
.route(web::patch().to(|| HttpResponse::Ok().body("patch!")))
.route(web::delete().to(|| HttpResponse::Ok().body("delete!"))),
.route(
web::put().to(|| async { HttpResponse::Ok().body("put!") }),
)
.route(
web::patch()
.to(|| async { HttpResponse::Ok().body("patch!") }),
)
.route(
web::delete()
.to(|| async { HttpResponse::Ok().body("delete!") }),
),
),
)
.await;
@ -567,13 +582,11 @@ mod tests {
#[test]
fn test_response() {
block_on(async {
let mut app = init_service(
App::new().service(
web::resource("/index.html")
.route(web::post().to(|| HttpResponse::Ok().body("welcome!"))),
),
)
.await;
let mut app =
init_service(App::new().service(web::resource("/index.html").route(
web::post().to(|| async { HttpResponse::Ok().body("welcome!") }),
)))
.await;
let req = TestRequest::post()
.uri("/index.html")
@ -597,7 +610,7 @@ mod tests {
let mut app =
init_service(App::new().service(web::resource("/people").route(
web::post().to(|person: web::Json<Person>| {
HttpResponse::Ok().json(person.into_inner())
async { HttpResponse::Ok().json(person.into_inner()) }
}),
)))
.await;
@ -621,7 +634,7 @@ mod tests {
let mut app =
init_service(App::new().service(web::resource("/people").route(
web::post().to(|person: web::Form<Person>| {
HttpResponse::Ok().json(person.into_inner())
async { HttpResponse::Ok().json(person.into_inner()) }
}),
)))
.await;
@ -650,7 +663,7 @@ mod tests {
let mut app =
init_service(App::new().service(web::resource("/people").route(
web::post().to(|person: web::Json<Person>| {
HttpResponse::Ok().json(person.into_inner())
async { HttpResponse::Ok().json(person.into_inner()) }
}),
)))
.await;
@ -688,8 +701,7 @@ mod tests {
}
let mut app = init_service(
App::new()
.service(web::resource("/index.html").to_async(async_with_block)),
App::new().service(web::resource("/index.html").to(async_with_block)),
)
.await;
@ -721,7 +733,7 @@ mod tests {
// let addr = run_on(|| MyActor.start());
// let mut app = init_service(App::new().service(
// web::resource("/index.html").to_async(move || {
// web::resource("/index.html").to(move || {
// addr.send(Num(1)).from_err().and_then(|res| {
// if res == 1 {
// HttpResponse::Ok()

View file

@ -181,7 +181,7 @@ impl<T: Serialize> Responder for Form<T> {
///
/// /// Extract form data using serde.
/// /// Custom configuration is used for this handler, max payload size is 4k
/// fn index(form: web::Form<FormData>) -> Result<String> {
/// async fn index(form: web::Form<FormData>) -> Result<String> {
/// Ok(format!("Welcome {}!", form.username))
/// }
///

View file

@ -46,7 +46,7 @@ use crate::responder::Responder;
/// }
///
/// /// deserialize `Info` from request's body
/// fn index(info: web::Json<Info>) -> String {
/// async fn index(info: web::Json<Info>) -> String {
/// format!("Welcome {}!", info.username)
/// }
///
@ -157,7 +157,7 @@ impl<T: Serialize> Responder for Json<T> {
/// }
///
/// /// deserialize `Info` from request's body
/// fn index(info: web::Json<Info>) -> String {
/// async fn index(info: web::Json<Info>) -> String {
/// format!("Welcome {}!", info.username)
/// }
///
@ -217,7 +217,7 @@ where
/// }
///
/// /// deserialize `Info` from request's body, max payload size is 4kb
/// fn index(info: web::Json<Info>) -> String {
/// async fn index(info: web::Json<Info>) -> String {
/// format!("Welcome {}!", info.username)
/// }
///

View file

@ -24,7 +24,7 @@ use crate::FromRequest;
/// /// extract path info from "/{username}/{count}/index.html" url
/// /// {username} - deserializes to a String
/// /// {count} - - deserializes to a u32
/// fn index(info: web::Path<(String, u32)>) -> String {
/// async fn index(info: web::Path<(String, u32)>) -> String {
/// format!("Welcome {}! {}", info.0, info.1)
/// }
///
@ -49,7 +49,7 @@ use crate::FromRequest;
/// }
///
/// /// extract `Info` from a path using serde
/// fn index(info: web::Path<Info>) -> Result<String, Error> {
/// async fn index(info: web::Path<Info>) -> Result<String, Error> {
/// Ok(format!("Welcome {}!", info.username))
/// }
///
@ -119,7 +119,7 @@ impl<T: fmt::Display> fmt::Display for Path<T> {
/// /// extract path info from "/{username}/{count}/index.html" url
/// /// {username} - deserializes to a String
/// /// {count} - - deserializes to a u32
/// fn index(info: web::Path<(String, u32)>) -> String {
/// async fn index(info: web::Path<(String, u32)>) -> String {
/// format!("Welcome {}! {}", info.0, info.1)
/// }
///
@ -144,7 +144,7 @@ impl<T: fmt::Display> fmt::Display for Path<T> {
/// }
///
/// /// extract `Info` from a path using serde
/// fn index(info: web::Path<Info>) -> Result<String, Error> {
/// async fn index(info: web::Path<Info>) -> Result<String, Error> {
/// Ok(format!("Welcome {}!", info.username))
/// }
///
@ -206,7 +206,7 @@ where
/// }
///
/// // deserialize `Info` from request's path
/// fn index(folder: web::Path<Folder>) -> String {
/// async fn index(folder: web::Path<Folder>) -> String {
/// format!("Selected folder: {:?}!", folder)
/// }
///

View file

@ -40,7 +40,7 @@ use crate::request::HttpRequest;
/// fn main() {
/// let app = App::new().service(
/// web::resource("/index.html").route(
/// web::get().to_async(index))
/// web::get().to(index))
/// );
/// }
/// ```
@ -88,7 +88,7 @@ impl Stream for Payload {
/// fn main() {
/// let app = App::new().service(
/// web::resource("/index.html").route(
/// web::get().to_async(index))
/// web::get().to(index))
/// );
/// }
/// ```
@ -117,7 +117,7 @@ impl FromRequest for Payload {
/// use actix_web::{web, App};
///
/// /// extract binary data from request
/// fn index(body: Bytes) -> String {
/// async fn index(body: Bytes) -> String {
/// format!("Body {:?}!", body)
/// }
///
@ -169,7 +169,7 @@ impl FromRequest for Bytes {
/// use actix_web::{web, App, FromRequest};
///
/// /// extract text data from request
/// fn index(text: String) -> String {
/// async fn index(text: String) -> String {
/// format!("Body {}!", text)
/// }
///

View file

@ -40,7 +40,7 @@ use crate::request::HttpRequest;
/// // Use `Query` extractor for query information (and destructure it within the signature).
/// // This handler gets called only if the request's query string contains a `username` field.
/// // The correct request for this handler would be `/index.html?id=64&response_type=Code"`.
/// fn index(web::Query(info): web::Query<AuthRequest>) -> String {
/// async fn index(web::Query(info): web::Query<AuthRequest>) -> String {
/// format!("Authorization request for client with id={} and type={:?}!", info.id, info.response_type)
/// }
///
@ -118,7 +118,7 @@ impl<T: fmt::Display> fmt::Display for Query<T> {
/// // Use `Query` extractor for query information.
/// // This handler get called only if request's query contains `username` field
/// // The correct request for this handler would be `/index.html?id=64&response_type=Code"`
/// fn index(info: web::Query<AuthRequest>) -> String {
/// async fn index(info: web::Query<AuthRequest>) -> String {
/// format!("Authorization request for client with id={} and type={:?}!", info.id, info.response_type)
/// }
///
@ -179,7 +179,7 @@ where
/// }
///
/// /// deserialize `Info` from request's querystring
/// fn index(info: web::Query<Info>) -> String {
/// async fn index(info: web::Query<Info>) -> String {
/// format!("Welcome {}!", info.username)
/// }
///

View file

@ -8,7 +8,7 @@ pub use futures::channel::oneshot::Canceled;
use crate::error::Error;
use crate::extract::FromRequest;
use crate::handler::{AsyncFactory, Factory};
use crate::handler::Factory;
use crate::resource::Resource;
use crate::responder::Responder;
use crate::route::Route;
@ -231,10 +231,10 @@ pub fn method(method: Method) -> Route {
/// Create a new route and add handler.
///
/// ```rust
/// use actix_web::{web, App, HttpResponse};
/// use actix_web::{web, App, HttpResponse, Responder};
///
/// fn index() -> HttpResponse {
/// unimplemented!()
/// async fn index() -> impl Responder {
/// HttpResponse::Ok()
/// }
///
/// App::new().service(
@ -242,36 +242,14 @@ pub fn method(method: Method) -> Route {
/// web::to(index))
/// );
/// ```
pub fn to<F, I, R>(handler: F) -> Route
pub fn to<F, I, R, U>(handler: F) -> Route
where
F: Factory<I, R> + 'static,
I: FromRequest + 'static,
R: Responder + 'static,
{
Route::new().to(handler)
}
/// Create a new route and add async handler.
///
/// ```rust
/// use actix_web::{web, App, HttpResponse, Error};
///
/// async fn index() -> Result<HttpResponse, Error> {
/// Ok(HttpResponse::Ok().finish())
/// }
///
/// App::new().service(web::resource("/").route(
/// web::to_async(index))
/// );
/// ```
pub fn to_async<F, I, R, U>(handler: F) -> Route
where
F: AsyncFactory<I, R, U>,
F: Factory<I, R, U>,
I: FromRequest + 'static,
R: Future<Output = U> + 'static,
U: Responder + 'static,
{
Route::new().to_async(handler)
Route::new().to(handler)
}
/// Create raw service for a specific path.

View file

@ -11,13 +11,11 @@ use bytes::Bytes;
use flate2::read::GzDecoder;
use flate2::write::{GzEncoder, ZlibDecoder, ZlibEncoder};
use flate2::Compression;
use futures::future::ok;
use futures::stream::once;
use futures::{future::ok, stream::once};
use rand::{distributions::Alphanumeric, Rng};
use actix_connect::start_default_resolver;
use actix_web::middleware::{BodyEncoding, Compress};
use actix_web::{dev, http, test, web, App, HttpResponse, HttpServer};
use actix_web::{dev, http, web, App, HttpResponse, HttpServer};
const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
@ -817,18 +815,19 @@ fn test_brotli_encoding_large() {
// }
#[cfg(all(
feature = "rust-tls",
feature = "ssl",
feature = "rustls",
feature = "openssl",
any(feature = "flate2-zlib", feature = "flate2-rust")
))]
#[test]
fn test_reading_deflate_encoding_large_random_ssl() {
block_on(async {
use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
use rustls::internal::pemfile::{certs, pkcs8_private_keys};
use rustls::{NoClientAuth, ServerConfig};
use open_ssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
use rust_tls::internal::pemfile::{certs, pkcs8_private_keys};
use rust_tls::{NoClientAuth, ServerConfig};
use std::fs::File;
use std::io::BufReader;
use std::sync::mpsc;
let addr = TestServer::unused_addr();
let (tx, rx) = mpsc::channel();
@ -838,7 +837,7 @@ fn test_reading_deflate_encoding_large_random_ssl() {
.take(160_000)
.collect::<String>();
thread::spawn(move || {
std::thread::spawn(move || {
let sys = actix_rt::System::new("test");
// load ssl keys
@ -851,11 +850,13 @@ fn test_reading_deflate_encoding_large_random_ssl() {
let srv = HttpServer::new(|| {
App::new().service(web::resource("/").route(web::to(|bytes: Bytes| {
Ok::<_, Error>(
HttpResponse::Ok()
.encoding(http::ContentEncoding::Identity)
.body(bytes),
)
async move {
Ok::<_, Error>(
HttpResponse::Ok()
.encoding(http::ContentEncoding::Identity)
.body(bytes),
)
}
})))
})
.bind_rustls(addr, config)
@ -866,8 +867,7 @@ fn test_reading_deflate_encoding_large_random_ssl() {
let _ = sys.run();
});
let (srv, _sys) = rx.recv().unwrap();
test::block_on(futures::lazy(|| Ok::<_, ()>(start_default_resolver()))).unwrap();
let client = test::run_on(|| {
let client = {
let mut builder = SslConnector::builder(SslMethod::tls()).unwrap();
builder.set_verify(SslVerifyMode::NONE);
let _ = builder.set_alpn_protos(b"\x02h2\x08http/1.1").unwrap();
@ -880,7 +880,7 @@ fn test_reading_deflate_encoding_large_random_ssl() {
.finish(),
)
.finish()
});
};
// encode data
let mut e = ZlibEncoder::new(Vec::new(), Compression::default());
@ -893,11 +893,11 @@ fn test_reading_deflate_encoding_large_random_ssl() {
.header(http::header::CONTENT_ENCODING, "deflate")
.send_body(enc);
let mut response = test::block_on(req).unwrap();
let mut response = req.await.unwrap();
assert!(response.status().is_success());
// read response
let bytes = test::block_on(response.body()).unwrap();
let bytes = response.body().await.unwrap();
assert_eq!(bytes.len(), data.len());
assert_eq!(bytes, Bytes::from(data));