Merge branch 'master' into router050

This commit is contained in:
Rob Ede 2022-02-22 07:07:22 +00:00 committed by GitHub
commit e31b8bad9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 177 additions and 65 deletions

View File

@ -108,8 +108,10 @@ pub(crate) enum Kind {
impl fmt::Debug for Error { impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// TODO: more detail f.debug_struct("actix_http::Error")
f.write_str("actix_http::Error") .field("kind", &self.inner.kind)
.field("cause", &self.inner.cause)
.finish()
} }
} }
@ -386,7 +388,6 @@ pub enum DispatchError {
impl StdError for DispatchError { impl StdError for DispatchError {
fn source(&self) -> Option<&(dyn StdError + 'static)> { fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self { match self {
// TODO: error source extraction?
DispatchError::Service(_res) => None, DispatchError::Service(_res) => None,
DispatchError::Body(err) => Some(&**err), DispatchError::Body(err) => Some(&**err),
DispatchError::Io(err) => Some(err), DispatchError::Io(err) => Some(err),

View File

@ -25,7 +25,9 @@ use pin_project_lite::pin_project;
use crate::{ use crate::{
body::{BodySize, BoxBody, MessageBody}, body::{BodySize, BoxBody, MessageBody},
config::ServiceConfig, config::ServiceConfig,
header::{HeaderValue, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING}, header::{
HeaderName, HeaderValue, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING, UPGRADE,
},
service::HttpFlow, service::HttpFlow,
Extensions, OnConnectData, Payload, Request, Response, ResponseHead, Extensions, OnConnectData, Payload, Request, Response, ResponseHead,
}; };
@ -306,13 +308,22 @@ fn prepare_response(
// copy headers // copy headers
for (key, value) in head.headers.iter() { for (key, value) in head.headers.iter() {
match *key { match key {
// TODO: consider skipping other headers according to: // omit HTTP/1.x only headers according to:
// https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.2 // https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.2
// omit HTTP/1.x only headers &CONNECTION | &TRANSFER_ENCODING | &UPGRADE => continue,
CONNECTION | TRANSFER_ENCODING => continue,
CONTENT_LENGTH if skip_len => continue, &CONTENT_LENGTH if skip_len => continue,
DATE => has_date = true, &DATE => has_date = true,
// omit HTTP/1.x only headers according to:
// https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.2
hdr if hdr == HeaderName::from_static("keep-alive")
|| hdr == HeaderName::from_static("proxy-connection") =>
{
continue
}
_ => {} _ => {}
} }

View File

@ -43,7 +43,7 @@ pub use actix_http_test::unused_addr;
use actix_service::{map_config, IntoServiceFactory, ServiceFactory, ServiceFactoryExt as _}; use actix_service::{map_config, IntoServiceFactory, ServiceFactory, ServiceFactoryExt as _};
pub use actix_web::test::{ pub use actix_web::test::{
call_and_read_body, call_and_read_body_json, call_service, init_service, ok_service, call_and_read_body, call_and_read_body_json, call_service, init_service, ok_service,
read_body, read_body_json, simple_service, TestRequest, read_body, read_body_json, status_service, TestRequest,
}; };
use actix_web::{ use actix_web::{
body::MessageBody, body::MessageBody,

View File

@ -1,6 +1,9 @@
# Changes # Changes
## Unreleased - 2021-xx-xx ## Unreleased - 2021-xx-xx
- Rename `test::{simple_service => status_service}`. [#2659]
[#2659]: https://github.com/actix/actix-web/pull/2659
## 4.0.0-rc.3 - 2022-02-08 ## 4.0.0-rc.3 - 2022-02-08

View File

@ -77,6 +77,7 @@ actix-web-codegen = { version = "0.5.0-rc.2", optional = true }
ahash = "0.7" ahash = "0.7"
bytes = "1" bytes = "1"
bytestring = "1"
cfg-if = "1" cfg-if = "1"
cookie = { version = "0.16", features = ["percent-encode"], optional = true } cookie = { version = "0.16", features = ["percent-encode"], optional = true }
derive_more = "0.99.5" derive_more = "0.99.5"

View File

@ -3,8 +3,7 @@
This guide walks you through the process of migrating from v3.x.y to v4.x.y. This guide walks you through the process of migrating from v3.x.y to v4.x.y.
If you are migrating to v4.x.y from an older version of Actix Web (v2.x.y or earlier), check out the other historical migration notes in this folder. If you are migrating to v4.x.y from an older version of Actix Web (v2.x.y or earlier), check out the other historical migration notes in this folder.
This document is not designed to be exhaustive - it focuses on the most significant changes coming in v4. This document is not designed to be exhaustive—it focuses on the most significant changes coming in v4. You can find an exhaustive changelog in [CHANGES.md](./CHANGES.md), complete of PR links. If you think that some of the changes that we omitted deserve to be called out in this document, please open an issue or submit a PR.
You can find an exhaustive changelog in [CHANGES.md](./CHANGES.md), complete of PR links. If you think that some of the changes that we omitted deserve to be called out in this document, please open an issue or submit a PR.
Headings marked with :warning: are **breaking behavioral changes**. They will probably not surface as compile-time errors though automated tests _might_ detect their effects on your app. Headings marked with :warning: are **breaking behavioral changes**. They will probably not surface as compile-time errors though automated tests _might_ detect their effects on your app.
@ -39,8 +38,9 @@ The MSRV of Actix Web has been raised from 1.42 to 1.54.
## Tokio v1 Ecosystem ## Tokio v1 Ecosystem
Actix Web v4 is now underpinned by `tokio`'s v1 ecosystem. Actix Web v4 is now underpinned by `tokio`'s v1 ecosystem.
`cargo` supports having multiple versions of the same crate within the same dependency tree, but `tokio` v1 does not interoperate transparently with its previous versions (v0.2, v0.1). Some of your dependencies might rely on `tokio`, either directly or indirectly - if they are using an older version of `tokio`, check if an update is available.
`cargo` supports having multiple versions of the same crate within the same dependency tree, but `tokio` v1 does not interoperate transparently with its previous versions (v0.2, v0.1). Some of your dependencies might rely on `tokio`, either directly or indirectly—if they are using an older version of `tokio`, check if an update is available.
The following command can help you to identify these dependencies: The following command can help you to identify these dependencies:
```sh ```sh
@ -59,8 +59,8 @@ Lots of modules have been re-organized in this release. If a compile error refer
## `NormalizePath` Middleware :warning: ## `NormalizePath` Middleware :warning:
The default `NormalizePath` behavior now strips trailing slashes by default. The default `NormalizePath` behavior now strips trailing slashes by default. This was the _documented_ behaviour in Actix Web v3, but the _actual_ behaviour differed. The discrepancy has now been resolved.
This was the _documented_ behaviour in Actix Web v3, but the _actual_ behaviour differed - the discrepancy has now been fixed.
As a consequence of this change, routes defined with trailing slashes will become inaccessible when using `NormalizePath::default()`. Calling `NormalizePath::default()` will log a warning. We suggest to use `new` or `trim`. As a consequence of this change, routes defined with trailing slashes will become inaccessible when using `NormalizePath::default()`. Calling `NormalizePath::default()` will log a warning. We suggest to use `new` or `trim`.
```diff ```diff
@ -103,8 +103,7 @@ The `compress` feature flag has been split into more granular feature flags, one
## `web::Path` ## `web::Path`
The inner field for `web::Path` is now private. The inner field for `web::Path` is now private. It was causing ambiguity when trying to use tuple indexing due to its `Deref` implementation.
It was causing too many issues when used with inner tuple types due to its `Deref` implementation.
```diff ```diff
- async fn handler(web::Path((foo, bar)): web::Path<(String, String)>) { - async fn handler(web::Path((foo, bar)): web::Path<(String, String)>) {
@ -118,7 +117,7 @@ Actix Web now depends on version 0.20 of `rustls`. As a result, the server confi
## Removed `awc` Client Re-export ## Removed `awc` Client Re-export
Actix Web's sister crate `awc` is no longer re-exported through the `client` module. This allows `awc` to have its own release cadence - its breaking changes are no longer blocked by Actix Web's (more conservative) release schedule. Actix Web's sister crate `awc` is no longer re-exported through the `client` module. This allows `awc` to have its own release cadenceits breaking changes are no longer blocked by Actix Web's (more conservative) release schedule.
```diff ```diff
- use actix_web::client::Client; - use actix_web::client::Client;
@ -134,11 +133,11 @@ Actix Web's sister crate `awc` is no longer re-exported through the `client` mod
+ use use actix_test::start; + use use actix_test::start;
``` ```
`TestServer` previously lived in `actix_web::test`, but it depends on `awc` which is no longer part of Actix Web's public API (see above). `TestServer` previously lived in `actix_web::test`, but it depends on `awc` which is no longer part of Actix Web's public API (see above).
## Header APIs ## Header APIs
Header related APIs have been standardized across all `actix-*` crates. The terminology now better matches the underlying `HeaderMap` naming conventions. Header related APIs have been standardized across all `actix-*` crates. The terminology now better matches the underlying `HeaderMap` naming conventions.
In short, "insert" always indicates that any existing headers with the same name are overridden, while "append" is used for adding with no removal (e.g. multi-valued headers). In short, "insert" always indicates that any existing headers with the same name are overridden, while "append" is used for adding with no removal (e.g. multi-valued headers).
@ -155,7 +154,7 @@ For request and response builder APIs, the new methods provide a unified interfa
+ .insert_header(ContentType::json()) + .insert_header(ContentType::json())
``` ```
We chose to deprecate most of the old methods instead of removing them immediately - the warning notes will guide you on how to update. We chose to deprecate most of the old methods instead of removing them immediatelythe warning notes will guide you on how to update.
## Response Body Types ## Response Body Types
@ -178,16 +177,65 @@ We have boosted the quality and completeness of the documentation for all items
### `BoxBody` ### `BoxBody`
`BoxBody` is a new type-erased body type. It's used for all error response bodies. `BoxBody` is a new type-erased body type.
Creating a boxed body is best done by calling [`.boxed()`](https://docs.rs/actix-web/4/actix_web/body/trait.MessageBody.html#method.boxed) on a `MessageBody` type.
It can be useful when writing handlers, responders, and middleware when you want to trade a (very) small amount of performance for a simpler type.
Creating a boxed body is done most efficiently by calling [`.boxed()`](https://docs.rs/actix-web/4/actix_web/body/trait.MessageBody.html#method.boxed) on a `MessageBody` type.
### `EitherBody` ### `EitherBody`
`EitherBody` is a new "either" type that is particularly useful in middlewares that can bail early, returning their own response plus body type. `EitherBody` is a new "either" type that implements `MessageBody`
It is particularly useful in middleware that can bail early, returning their own response plus body type. By default the "right" variant is `BoxBody` (i.e., `EitherBody<B>` === `EitherBody<B, BoxBody>`) but it can be anything that implements `MessageBody`.
For example, it will be common among middleware which value performance of the hot path to use:
```rust
type Response = Result<ServiceResponse<EitherBody<B>>, Error>
```
This can be read (ignoring the `Result`) as "resolves with a `ServiceResponse` that is either the inner service's `B` body type or a boxed body type from elsewhere, likely constructed within the middleware itself". Of course, if your middleware contains only simple string other/error responses, it's possible to use them without boxes at the cost of a less simple implementation:
```rust
type Response = Result<ServiceResponse<EitherBody<B, String>>, Error>
```
### Error Handlers ### Error Handlers
TODO In particular, folks seem to be struggling with the `ErrorHandlers` middleware because of this change and the obscured nature of `EitherBody` within its types. `ErrorHandlers` is a commonly used middleware that has changed in design slightly due to the other body type changes.
In particular, an implicit `EitherBody` is used in the `ErrorHandlerResponse<B>` type. An `ErrorHandlerResponse<B>` now expects a `ServiceResponse<EitherBody<B>>` to be returned within response variants. The following is a migration for an error handler that **only modifies** the response argument (left body).
```diff
fn add_error_header<B>(mut res: ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>, Error> {
res.response_mut().headers_mut().insert(
header::CONTENT_TYPE,
header::HeaderValue::from_static("Error"),
);
- Ok(ErrorHandlerResponse::Response(res))
+ Ok(ErrorHandlerResponse::Response(res.map_into_left_body()))
}
```
The following is a migration for an error handler that creates a new response instead (right body).
```diff
fn error_handler<B>(res: ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>, Error> {
- let req = res.request().clone();
+ let (req, _res) = res.into_parts();
let res = actix_files::NamedFile::open("./templates/404.html")?
.set_status_code(StatusCode::NOT_FOUND)
- .into_response(&req)?
- .into_body();
+ .into_response(&req);
- let res = ServiceResponse::new(req, res);
+ let res = ServiceResponse::new(req, res).map_into_right_body();
Ok(ErrorHandlerResponse::Response(res))
}
```
## Middleware Trait APIs ## Middleware Trait APIs
@ -251,7 +299,7 @@ You may need to review the [guidance on shared mutable state](https://docs.rs/ac
Improvements to module management and re-exports have resulted in not needing direct dependencies on these underlying crates for the vast majority of cases. In particular: Improvements to module management and re-exports have resulted in not needing direct dependencies on these underlying crates for the vast majority of cases. In particular:
- all traits necessary for creating middlewares are now re-exported through the `dev` modules; - all traits necessary for creating middlewares are now re-exported through the `dev` modules;
- `#[actix_web::test]` now exists for async test definitions. - `#[actix_web::test]` now exists for async test definitions.
Relying on these re-exports will ease the transition to future versions of Actix Web. Relying on these re-exports will ease the transition to future versions of Actix Web.

View File

@ -185,6 +185,7 @@ mod tests {
use super::*; use super::*;
use crate::{ use crate::{
body,
http::{ http::{
header::{HeaderValue, CONTENT_TYPE}, header::{HeaderValue, CONTENT_TYPE},
StatusCode, StatusCode,
@ -203,7 +204,7 @@ mod tests {
Ok(ErrorHandlerResponse::Response(res.map_into_left_body())) Ok(ErrorHandlerResponse::Response(res.map_into_left_body()))
} }
let srv = test::simple_service(StatusCode::INTERNAL_SERVER_ERROR); let srv = test::status_service(StatusCode::INTERNAL_SERVER_ERROR);
let mw = ErrorHandlers::new() let mw = ErrorHandlers::new()
.handler(StatusCode::INTERNAL_SERVER_ERROR, error_handler) .handler(StatusCode::INTERNAL_SERVER_ERROR, error_handler)
@ -230,7 +231,7 @@ mod tests {
)) ))
} }
let srv = test::simple_service(StatusCode::INTERNAL_SERVER_ERROR); let srv = test::status_service(StatusCode::INTERNAL_SERVER_ERROR);
let mw = ErrorHandlers::new() let mw = ErrorHandlers::new()
.handler(StatusCode::INTERNAL_SERVER_ERROR, error_handler) .handler(StatusCode::INTERNAL_SERVER_ERROR, error_handler)
@ -245,9 +246,7 @@ mod tests {
#[actix_rt::test] #[actix_rt::test]
async fn changes_body_type() { async fn changes_body_type() {
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn error_handler<B: 'static>( fn error_handler<B>(res: ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>> {
res: ServiceResponse<B>,
) -> Result<ErrorHandlerResponse<B>> {
let (req, res) = res.into_parts(); let (req, res) = res.into_parts();
let res = res.set_body(Bytes::from("sorry, that's no bueno")); let res = res.set_body(Bytes::from("sorry, that's no bueno"));
@ -258,7 +257,7 @@ mod tests {
Ok(ErrorHandlerResponse::Response(res)) Ok(ErrorHandlerResponse::Response(res))
} }
let srv = test::simple_service(StatusCode::INTERNAL_SERVER_ERROR); let srv = test::status_service(StatusCode::INTERNAL_SERVER_ERROR);
let mw = ErrorHandlers::new() let mw = ErrorHandlers::new()
.handler(StatusCode::INTERNAL_SERVER_ERROR, error_handler) .handler(StatusCode::INTERNAL_SERVER_ERROR, error_handler)
@ -270,5 +269,33 @@ mod tests {
assert_eq!(test::read_body(res).await, "sorry, that's no bueno"); assert_eq!(test::read_body(res).await, "sorry, that's no bueno");
} }
// TODO: test where error is thrown #[actix_rt::test]
async fn error_thrown() {
#[allow(clippy::unnecessary_wraps)]
fn error_handler<B>(_res: ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>> {
Err(crate::error::ErrorInternalServerError(
"error in error handler",
))
}
let srv = test::status_service(StatusCode::BAD_REQUEST);
let mw = ErrorHandlers::new()
.handler(StatusCode::BAD_REQUEST, error_handler)
.new_transform(srv.into_service())
.await
.unwrap();
let err = mw
.call(TestRequest::default().to_srv_request())
.await
.unwrap_err();
let res = err.error_response();
assert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR);
assert_eq!(
body::to_bytes(res.into_body()).await.unwrap(),
"error in error handler"
);
}
} }

View File

@ -7,14 +7,35 @@ use actix_http::{
}; };
use bytes::{Bytes, BytesMut}; use bytes::{Bytes, BytesMut};
use crate::{Error, HttpRequest, HttpResponse};
use super::CustomizeResponder; use super::CustomizeResponder;
use crate::{Error, HttpRequest, HttpResponse};
/// Trait implemented by types that can be converted to an HTTP response. /// Trait implemented by types that can be converted to an HTTP response.
/// ///
/// Any types that implement this trait can be used in the return type of a handler. /// Any types that implement this trait can be used in the return type of a handler. Since handlers
// # TODO: more about implementation notes and foreign impls /// will only have one return type, it is idiomatic to use opaque return types `-> impl Responder`.
///
/// # Implementations
/// It is often not required to implement `Responder` for your own types due to a broad base of
/// built-in implementations:
/// - `HttpResponse` and `HttpResponseBuilder`
/// - `Option<R>` where `R: Responder`
/// - `Result<R, E>` where `R: Responder` and [`E: ResponseError`](crate::ResponseError)
/// - `(R, StatusCode) where `R: Responder`
/// - `&'static str`, `String`, `&'_ String`, `Cow<'_, str>`, [`ByteString`](bytestring::ByteString)
/// - `&'static [u8]`, `Vec<u8>`, `Bytes`, `BytesMut`
/// - [`Json<T>`](crate::web::Json) and [`Form<T>`](crate::web::Form) where `T: Serialize`
/// - [`Either<L, R>`](crate::web::Either) where `L: Serialize` and `R: Serialize`
/// - [`CustomizeResponder<R>`]
/// - [`actix_files::NamedFile`](https://docs.rs/actix-files/latest/actix_files/struct.NamedFile.html)
/// - [Experimental responders from `actix-web-lab`](https://docs.rs/actix-web-lab/latest/actix_web_lab/respond/index.html)
/// - Third party integrations may also have implemented `Responder` where appropriate. For example,
/// HTML templating engines.
///
/// # Customizing Responder Output
/// Calling [`.customize()`](Responder::customize) on any responder type will wrap it in a
/// [`CustomizeResponder`] capable of overriding various parts of the response such as the status
/// code and header map.
pub trait Responder { pub trait Responder {
type Body: MessageBody + 'static; type Body: MessageBody + 'static;
@ -23,7 +44,7 @@ pub trait Responder {
/// Wraps responder to allow alteration of its response. /// Wraps responder to allow alteration of its response.
/// ///
/// See [`CustomizeResponder`] docs for its capabilities. /// See [`CustomizeResponder`] docs for more details on its capabilities.
/// ///
/// # Examples /// # Examples
/// ``` /// ```
@ -84,11 +105,8 @@ impl Responder for actix_http::ResponseBuilder {
} }
} }
impl<T> Responder for Option<T> impl<R: Responder> Responder for Option<R> {
where type Body = EitherBody<R::Body>;
T: Responder,
{
type Body = EitherBody<T::Body>;
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> { fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
match self { match self {
@ -98,12 +116,12 @@ where
} }
} }
impl<T, E> Responder for Result<T, E> impl<R, E> Responder for Result<R, E>
where where
T: Responder, R: Responder,
E: Into<Error>, E: Into<Error>,
{ {
type Body = EitherBody<T::Body>; type Body = EitherBody<R::Body>;
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> { fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
match self { match self {
@ -113,8 +131,8 @@ where
} }
} }
impl<T: Responder> Responder for (T, StatusCode) { impl<R: Responder> Responder for (R, StatusCode) {
type Body = T::Body; type Body = R::Body;
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> { fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
let mut res = self.0.respond_to(req); let mut res = self.0.respond_to(req);
@ -147,6 +165,7 @@ impl_responder_by_forward_into_base_response!(BytesMut);
impl_responder_by_forward_into_base_response!(&'static str); impl_responder_by_forward_into_base_response!(&'static str);
impl_responder_by_forward_into_base_response!(String); impl_responder_by_forward_into_base_response!(String);
impl_responder_by_forward_into_base_response!(bytestring::ByteString);
macro_rules! impl_into_string_responder { macro_rules! impl_into_string_responder {
($res:ty) => { ($res:ty) => {

View File

@ -323,12 +323,6 @@ impl From<Error> for HttpResponse {
impl<B> From<HttpResponse<B>> for Response<B> { impl<B> From<HttpResponse<B>> for Response<B> {
fn from(res: HttpResponse<B>) -> Self { fn from(res: HttpResponse<B>) -> Self {
// this impl will always be called as part of dispatcher // this impl will always be called as part of dispatcher
// TODO: expose cause somewhere?
// if let Some(err) = res.error {
// return Response::from_error(err);
// }
res.res res.res
} }
} }

View File

@ -5,7 +5,7 @@
//! //!
//! # Off-The-Shelf Test Services //! # Off-The-Shelf Test Services
//! - [`ok_service`] //! - [`ok_service`]
//! - [`simple_service`] //! - [`status_service`]
//! //!
//! # Calling Test Service //! # Calling Test Service
//! - [`TestRequest`] //! - [`TestRequest`]
@ -27,7 +27,7 @@ mod test_utils;
pub use self::test_request::TestRequest; pub use self::test_request::TestRequest;
#[allow(deprecated)] #[allow(deprecated)]
pub use self::test_services::{default_service, ok_service, simple_service}; pub use self::test_services::{default_service, ok_service, simple_service, status_service};
#[allow(deprecated)] #[allow(deprecated)]
pub use self::test_utils::{ pub use self::test_utils::{
call_and_read_body, call_and_read_body_json, call_service, init_service, read_body, call_and_read_body, call_and_read_body_json, call_service, init_service, read_body,

View File

@ -10,11 +10,11 @@ use crate::{
/// Creates service that always responds with `200 OK` and no body. /// Creates service that always responds with `200 OK` and no body.
pub fn ok_service( pub fn ok_service(
) -> impl Service<ServiceRequest, Response = ServiceResponse<BoxBody>, Error = Error> { ) -> impl Service<ServiceRequest, Response = ServiceResponse<BoxBody>, Error = Error> {
simple_service(StatusCode::OK) status_service(StatusCode::OK)
} }
/// Creates service that always responds with given status code and no body. /// Creates service that always responds with given status code and no body.
pub fn simple_service( pub fn status_service(
status_code: StatusCode, status_code: StatusCode,
) -> impl Service<ServiceRequest, Response = ServiceResponse<BoxBody>, Error = Error> { ) -> impl Service<ServiceRequest, Response = ServiceResponse<BoxBody>, Error = Error> {
fn_service(move |req: ServiceRequest| { fn_service(move |req: ServiceRequest| {
@ -23,9 +23,17 @@ pub fn simple_service(
} }
#[doc(hidden)] #[doc(hidden)]
#[deprecated(since = "4.0.0", note = "Renamed to `simple_service`.")] #[deprecated(since = "4.0.0", note = "Renamed to `status_service`.")]
pub fn simple_service(
status_code: StatusCode,
) -> impl Service<ServiceRequest, Response = ServiceResponse<BoxBody>, Error = Error> {
status_service(status_code)
}
#[doc(hidden)]
#[deprecated(since = "4.0.0", note = "Renamed to `status_service`.")]
pub fn default_service( pub fn default_service(
status_code: StatusCode, status_code: StatusCode,
) -> impl Service<ServiceRequest, Response = ServiceResponse<BoxBody>, Error = Error> { ) -> impl Service<ServiceRequest, Response = ServiceResponse<BoxBody>, Error = Error> {
simple_service(status_code) status_service(status_code)
} }

View File

@ -89,7 +89,7 @@ where
/// ``` /// ```
/// ///
/// # Panics /// # Panics
/// Panics if service call returns error. /// Panics if service call returns error. To handle errors use `app.call(req)`.
pub async fn call_service<S, R, B, E>(app: &S, req: R) -> S::Response pub async fn call_service<S, R, B, E>(app: &S, req: R) -> S::Response
where where
S: Service<R, Response = ServiceResponse<B>, Error = E>, S: Service<R, Response = ServiceResponse<B>, Error = E>,

View File

@ -232,7 +232,7 @@ where
None => { None => {
let (io, proto) = connector.call(req).await?; let (io, proto) = connector.call(req).await?;
// TODO: remove when http3 is added in support. // NOTE: remove when http3 is added in support.
assert!(proto != Protocol::Http3); assert!(proto != Protocol::Http3);
if proto == Protocol::Http1 { if proto == Protocol::Http1 {