mirror of
https://github.com/tokio-rs/axum.git
synced 2026-09-07 00:00:12 +02:00
Merge remote-tracking branch 'origin/main' into david/dont-override-status-codes-of-5xx
This commit is contained in:
+37
-2
@@ -5,9 +5,44 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
# Unreleased
|
||||
# 0.5.0
|
||||
|
||||
- None.
|
||||
## alpha.1
|
||||
|
||||
- **breaking:** Replace `#[async_trait]` with [return-position `impl Trait` in traits][RPITIT] ([#2308])
|
||||
- **change:** Update minimum rust version to 1.75 ([#2943])
|
||||
|
||||
[RPITIT]: https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html
|
||||
[#2308]: https://github.com/tokio-rs/axum/pull/2308
|
||||
[#2943]: https://github.com/tokio-rs/axum/pull/2943
|
||||
|
||||
# 0.4.5
|
||||
|
||||
- **fixed:** Compile errors from the internal `__log_rejection` macro under
|
||||
certain Cargo feature combinations between axum crates ([#2933])
|
||||
|
||||
[#2933]: https://github.com/tokio-rs/axum/pull/2933
|
||||
|
||||
# 0.4.4
|
||||
|
||||
- **added:** Derive `Clone` and `Copy` for `AppendHeaders` ([#2776])
|
||||
- **added:** `must_use` attribute on `AppendHeaders` ([#2846])
|
||||
- **added:** `must_use` attribute on `ErrorResponse` ([#2846])
|
||||
- **added:** `must_use` attribute on `IntoResponse::into_response` ([#2846])
|
||||
- **added:** `must_use` attribute on `IntoResponseParts` trait methods ([#2846])
|
||||
- **added:** Implement `Copy` for `DefaultBodyLimit` ([#2875])
|
||||
- **added**: `DefaultBodyLimit::max` and `DefaultBodyLimit::disable` are now
|
||||
allowed in const context ([#2875])
|
||||
|
||||
[#2776]: https://github.com/tokio-rs/axum/pull/2776
|
||||
[#2846]: https://github.com/tokio-rs/axum/pull/2846
|
||||
[#2875]: https://github.com/tokio-rs/axum/pull/2875
|
||||
|
||||
# 0.4.3 (13. January, 2024)
|
||||
|
||||
- **added:** Implement `IntoResponseParts` for `()` ([#2471])
|
||||
|
||||
[#2471]: https://github.com/tokio-rs/axum/pull/2471
|
||||
|
||||
# 0.4.2 (29. December, 2023)
|
||||
|
||||
|
||||
+11
-12
@@ -2,14 +2,14 @@
|
||||
categories = ["asynchronous", "network-programming", "web-programming"]
|
||||
description = "Core types and traits for axum"
|
||||
edition = "2021"
|
||||
rust-version = "1.56"
|
||||
rust-version = { workspace = true }
|
||||
homepage = "https://github.com/tokio-rs/axum"
|
||||
keywords = ["http", "web", "framework"]
|
||||
license = "MIT"
|
||||
name = "axum-core"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/tokio-rs/axum"
|
||||
version = "0.4.2" # remember to also bump the version that axum and axum-extra depend on
|
||||
version = "0.5.0-alpha.1" # remember to bump the version that axum and axum-extra depend on
|
||||
|
||||
[features]
|
||||
tracing = ["dep:tracing"]
|
||||
@@ -18,32 +18,29 @@ tracing = ["dep:tracing"]
|
||||
__private_docs = ["dep:tower-http"]
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1.67"
|
||||
bytes = "1.0"
|
||||
bytes = "1.2"
|
||||
futures-util = { version = "0.3", default-features = false, features = ["alloc"] }
|
||||
http = "1.0.0"
|
||||
http-body = "1.0.0"
|
||||
http-body-util = "0.1.0"
|
||||
mime = "0.3.16"
|
||||
pin-project-lite = "0.2.7"
|
||||
sync_wrapper = "0.1.1"
|
||||
rustversion = "1.0.9"
|
||||
sync_wrapper = "1.0.0"
|
||||
tower-layer = "0.3"
|
||||
tower-service = "0.3"
|
||||
|
||||
# optional dependencies
|
||||
tower-http = { version = "0.5.0", optional = true, features = ["limit"] }
|
||||
tower-http = { version = "0.6.0", optional = true, features = ["limit"] }
|
||||
tracing = { version = "0.1.37", default-features = false, optional = true }
|
||||
|
||||
[build-dependencies]
|
||||
rustversion = "1.0.9"
|
||||
|
||||
[dev-dependencies]
|
||||
axum = { path = "../axum", version = "0.7.2" }
|
||||
axum = { path = "../axum" }
|
||||
axum-extra = { path = "../axum-extra", features = ["typed-header"] }
|
||||
futures-util = { version = "0.3", default-features = false, features = ["alloc"] }
|
||||
hyper = "1.0.0"
|
||||
tokio = { version = "1.25.0", features = ["macros"] }
|
||||
tower-http = { version = "0.5.0", features = ["limit"] }
|
||||
tower-http = { version = "0.6.0", features = ["limit"] }
|
||||
|
||||
[package.metadata.cargo-public-api-crates]
|
||||
allowed = [
|
||||
@@ -57,6 +54,8 @@ allowed = [
|
||||
"http_body",
|
||||
]
|
||||
|
||||
[package.metadata.cargo-machete]
|
||||
ignored = ["tower-http"] # See __private_docs feature
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ This crate uses `#![forbid(unsafe_code)]` to ensure everything is implemented in
|
||||
|
||||
## Minimum supported Rust version
|
||||
|
||||
axum-core's MSRV is 1.56.
|
||||
axum-core's MSRV is 1.75.
|
||||
|
||||
## Getting Help
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#[rustversion::nightly]
|
||||
fn main() {
|
||||
println!("cargo:rustc-cfg=nightly_error_messages");
|
||||
}
|
||||
|
||||
#[rustversion::not(nightly)]
|
||||
fn main() {}
|
||||
@@ -6,13 +6,11 @@ mod tests {
|
||||
use std::convert::Infallible;
|
||||
|
||||
use crate::extract::{FromRef, FromRequestParts};
|
||||
use async_trait::async_trait;
|
||||
use http::request::Parts;
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub(crate) struct State<S>(pub(crate) S);
|
||||
|
||||
#[async_trait]
|
||||
impl<OuterState, InnerState> FromRequestParts<OuterState> for State<InnerState>
|
||||
where
|
||||
InnerState: FromRef<OuterState>,
|
||||
@@ -30,9 +28,9 @@ mod tests {
|
||||
}
|
||||
|
||||
// some extractor that requires the state, such as `SignedCookieJar`
|
||||
#[allow(dead_code)]
|
||||
pub(crate) struct RequiresState(pub(crate) String);
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequestParts<S> for RequiresState
|
||||
where
|
||||
S: Send + Sync,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::body::Body;
|
||||
use crate::extract::{DefaultBodyLimitKind, FromRequest, FromRequestParts, Request};
|
||||
use futures_util::future::BoxFuture;
|
||||
use std::future::Future;
|
||||
|
||||
mod sealed {
|
||||
pub trait Sealed {}
|
||||
@@ -20,7 +20,6 @@ pub trait RequestExt: sealed::Sealed + Sized {
|
||||
///
|
||||
/// ```
|
||||
/// use axum::{
|
||||
/// async_trait,
|
||||
/// extract::{Request, FromRequest},
|
||||
/// body::Body,
|
||||
/// http::{header::CONTENT_TYPE, StatusCode},
|
||||
@@ -30,7 +29,6 @@ pub trait RequestExt: sealed::Sealed + Sized {
|
||||
///
|
||||
/// struct FormOrJson<T>(T);
|
||||
///
|
||||
/// #[async_trait]
|
||||
/// impl<S, T> FromRequest<S> for FormOrJson<T>
|
||||
/// where
|
||||
/// Json<T>: FromRequest<()>,
|
||||
@@ -67,7 +65,7 @@ pub trait RequestExt: sealed::Sealed + Sized {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn extract<E, M>(self) -> BoxFuture<'static, Result<E, E::Rejection>>
|
||||
fn extract<E, M>(self) -> impl Future<Output = Result<E, E::Rejection>> + Send
|
||||
where
|
||||
E: FromRequest<(), M> + 'static,
|
||||
M: 'static;
|
||||
@@ -83,7 +81,6 @@ pub trait RequestExt: sealed::Sealed + Sized {
|
||||
///
|
||||
/// ```
|
||||
/// use axum::{
|
||||
/// async_trait,
|
||||
/// body::Body,
|
||||
/// extract::{Request, FromRef, FromRequest},
|
||||
/// RequestExt,
|
||||
@@ -93,7 +90,6 @@ pub trait RequestExt: sealed::Sealed + Sized {
|
||||
/// requires_state: RequiresState,
|
||||
/// }
|
||||
///
|
||||
/// #[async_trait]
|
||||
/// impl<S> FromRequest<S> for MyExtractor
|
||||
/// where
|
||||
/// String: FromRef<S>,
|
||||
@@ -111,7 +107,6 @@ pub trait RequestExt: sealed::Sealed + Sized {
|
||||
/// // some extractor that consumes the request body and requires state
|
||||
/// struct RequiresState { /* ... */ }
|
||||
///
|
||||
/// #[async_trait]
|
||||
/// impl<S> FromRequest<S> for RequiresState
|
||||
/// where
|
||||
/// String: FromRef<S>,
|
||||
@@ -124,7 +119,10 @@ pub trait RequestExt: sealed::Sealed + Sized {
|
||||
/// # }
|
||||
/// }
|
||||
/// ```
|
||||
fn extract_with_state<E, S, M>(self, state: &S) -> BoxFuture<'_, Result<E, E::Rejection>>
|
||||
fn extract_with_state<E, S, M>(
|
||||
self,
|
||||
state: &S,
|
||||
) -> impl Future<Output = Result<E, E::Rejection>> + Send
|
||||
where
|
||||
E: FromRequest<S, M> + 'static,
|
||||
S: Send + Sync;
|
||||
@@ -137,7 +135,6 @@ pub trait RequestExt: sealed::Sealed + Sized {
|
||||
///
|
||||
/// ```
|
||||
/// use axum::{
|
||||
/// async_trait,
|
||||
/// extract::{Path, Request, FromRequest},
|
||||
/// response::{IntoResponse, Response},
|
||||
/// body::Body,
|
||||
@@ -154,7 +151,6 @@ pub trait RequestExt: sealed::Sealed + Sized {
|
||||
/// payload: T,
|
||||
/// }
|
||||
///
|
||||
/// #[async_trait]
|
||||
/// impl<S, T> FromRequest<S> for MyExtractor<T>
|
||||
/// where
|
||||
/// S: Send + Sync,
|
||||
@@ -179,7 +175,7 @@ pub trait RequestExt: sealed::Sealed + Sized {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn extract_parts<E>(&mut self) -> BoxFuture<'_, Result<E, E::Rejection>>
|
||||
fn extract_parts<E>(&mut self) -> impl Future<Output = Result<E, E::Rejection>> + Send
|
||||
where
|
||||
E: FromRequestParts<()> + 'static;
|
||||
|
||||
@@ -191,7 +187,6 @@ pub trait RequestExt: sealed::Sealed + Sized {
|
||||
///
|
||||
/// ```
|
||||
/// use axum::{
|
||||
/// async_trait,
|
||||
/// extract::{Request, FromRef, FromRequest, FromRequestParts},
|
||||
/// http::request::Parts,
|
||||
/// response::{IntoResponse, Response},
|
||||
@@ -204,7 +199,6 @@ pub trait RequestExt: sealed::Sealed + Sized {
|
||||
/// payload: T,
|
||||
/// }
|
||||
///
|
||||
/// #[async_trait]
|
||||
/// impl<S, T> FromRequest<S> for MyExtractor<T>
|
||||
/// where
|
||||
/// String: FromRef<S>,
|
||||
@@ -234,7 +228,6 @@ pub trait RequestExt: sealed::Sealed + Sized {
|
||||
///
|
||||
/// struct RequiresState {}
|
||||
///
|
||||
/// #[async_trait]
|
||||
/// impl<S> FromRequestParts<S> for RequiresState
|
||||
/// where
|
||||
/// String: FromRef<S>,
|
||||
@@ -250,7 +243,7 @@ pub trait RequestExt: sealed::Sealed + Sized {
|
||||
fn extract_parts_with_state<'a, E, S>(
|
||||
&'a mut self,
|
||||
state: &'a S,
|
||||
) -> BoxFuture<'a, Result<E, E::Rejection>>
|
||||
) -> impl Future<Output = Result<E, E::Rejection>> + Send + 'a
|
||||
where
|
||||
E: FromRequestParts<S> + 'static,
|
||||
S: Send + Sync;
|
||||
@@ -267,7 +260,7 @@ pub trait RequestExt: sealed::Sealed + Sized {
|
||||
}
|
||||
|
||||
impl RequestExt for Request {
|
||||
fn extract<E, M>(self) -> BoxFuture<'static, Result<E, E::Rejection>>
|
||||
fn extract<E, M>(self) -> impl Future<Output = Result<E, E::Rejection>> + Send
|
||||
where
|
||||
E: FromRequest<(), M> + 'static,
|
||||
M: 'static,
|
||||
@@ -275,7 +268,10 @@ impl RequestExt for Request {
|
||||
self.extract_with_state(&())
|
||||
}
|
||||
|
||||
fn extract_with_state<E, S, M>(self, state: &S) -> BoxFuture<'_, Result<E, E::Rejection>>
|
||||
fn extract_with_state<E, S, M>(
|
||||
self,
|
||||
state: &S,
|
||||
) -> impl Future<Output = Result<E, E::Rejection>> + Send
|
||||
where
|
||||
E: FromRequest<S, M> + 'static,
|
||||
S: Send + Sync,
|
||||
@@ -283,17 +279,17 @@ impl RequestExt for Request {
|
||||
E::from_request(self, state)
|
||||
}
|
||||
|
||||
fn extract_parts<E>(&mut self) -> BoxFuture<'_, Result<E, E::Rejection>>
|
||||
fn extract_parts<E>(&mut self) -> impl Future<Output = Result<E, E::Rejection>> + Send
|
||||
where
|
||||
E: FromRequestParts<()> + 'static,
|
||||
{
|
||||
self.extract_parts_with_state(&())
|
||||
}
|
||||
|
||||
fn extract_parts_with_state<'a, E, S>(
|
||||
async fn extract_parts_with_state<'a, E, S>(
|
||||
&'a mut self,
|
||||
state: &'a S,
|
||||
) -> BoxFuture<'a, Result<E, E::Rejection>>
|
||||
) -> Result<E, E::Rejection>
|
||||
where
|
||||
E: FromRequestParts<S> + 'static,
|
||||
S: Send + Sync,
|
||||
@@ -306,17 +302,15 @@ impl RequestExt for Request {
|
||||
*req.extensions_mut() = std::mem::take(self.extensions_mut());
|
||||
let (mut parts, ()) = req.into_parts();
|
||||
|
||||
Box::pin(async move {
|
||||
let result = E::from_request_parts(&mut parts, state).await;
|
||||
let result = E::from_request_parts(&mut parts, state).await;
|
||||
|
||||
*self.version_mut() = parts.version;
|
||||
*self.method_mut() = parts.method.clone();
|
||||
*self.uri_mut() = parts.uri.clone();
|
||||
*self.headers_mut() = std::mem::take(&mut parts.headers);
|
||||
*self.extensions_mut() = std::mem::take(&mut parts.extensions);
|
||||
*self.version_mut() = parts.version;
|
||||
*self.method_mut() = parts.method.clone();
|
||||
*self.uri_mut() = parts.uri.clone();
|
||||
*self.headers_mut() = std::mem::take(&mut parts.headers);
|
||||
*self.extensions_mut() = std::mem::take(&mut parts.extensions);
|
||||
|
||||
result
|
||||
})
|
||||
result
|
||||
}
|
||||
|
||||
fn with_limited_body(self) -> Request {
|
||||
@@ -345,7 +339,6 @@ mod tests {
|
||||
ext_traits::tests::{RequiresState, State},
|
||||
extract::FromRef,
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use http::Method;
|
||||
|
||||
#[tokio::test]
|
||||
@@ -414,7 +407,6 @@ mod tests {
|
||||
body: String,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequest<S> for WorksForCustomExtractor
|
||||
where
|
||||
S: Send + Sync,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::extract::FromRequestParts;
|
||||
use futures_util::future::BoxFuture;
|
||||
use http::request::Parts;
|
||||
use std::future::Future;
|
||||
|
||||
mod sealed {
|
||||
pub trait Sealed {}
|
||||
@@ -21,7 +21,6 @@ pub trait RequestPartsExt: sealed::Sealed + Sized {
|
||||
/// response::{Response, IntoResponse},
|
||||
/// http::request::Parts,
|
||||
/// RequestPartsExt,
|
||||
/// async_trait,
|
||||
/// };
|
||||
/// use std::collections::HashMap;
|
||||
///
|
||||
@@ -30,7 +29,6 @@ pub trait RequestPartsExt: sealed::Sealed + Sized {
|
||||
/// query_params: HashMap<String, String>,
|
||||
/// }
|
||||
///
|
||||
/// #[async_trait]
|
||||
/// impl<S> FromRequestParts<S> for MyExtractor
|
||||
/// where
|
||||
/// S: Send + Sync,
|
||||
@@ -54,7 +52,7 @@ pub trait RequestPartsExt: sealed::Sealed + Sized {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn extract<E>(&mut self) -> BoxFuture<'_, Result<E, E::Rejection>>
|
||||
fn extract<E>(&mut self) -> impl Future<Output = Result<E, E::Rejection>> + Send
|
||||
where
|
||||
E: FromRequestParts<()> + 'static;
|
||||
|
||||
@@ -70,14 +68,12 @@ pub trait RequestPartsExt: sealed::Sealed + Sized {
|
||||
/// response::{Response, IntoResponse},
|
||||
/// http::request::Parts,
|
||||
/// RequestPartsExt,
|
||||
/// async_trait,
|
||||
/// };
|
||||
///
|
||||
/// struct MyExtractor {
|
||||
/// requires_state: RequiresState,
|
||||
/// }
|
||||
///
|
||||
/// #[async_trait]
|
||||
/// impl<S> FromRequestParts<S> for MyExtractor
|
||||
/// where
|
||||
/// String: FromRef<S>,
|
||||
@@ -97,7 +93,6 @@ pub trait RequestPartsExt: sealed::Sealed + Sized {
|
||||
/// struct RequiresState { /* ... */ }
|
||||
///
|
||||
/// // some extractor that requires a `String` in the state
|
||||
/// #[async_trait]
|
||||
/// impl<S> FromRequestParts<S> for RequiresState
|
||||
/// where
|
||||
/// String: FromRef<S>,
|
||||
@@ -113,14 +108,14 @@ pub trait RequestPartsExt: sealed::Sealed + Sized {
|
||||
fn extract_with_state<'a, E, S>(
|
||||
&'a mut self,
|
||||
state: &'a S,
|
||||
) -> BoxFuture<'a, Result<E, E::Rejection>>
|
||||
) -> impl Future<Output = Result<E, E::Rejection>> + Send + 'a
|
||||
where
|
||||
E: FromRequestParts<S> + 'static,
|
||||
S: Send + Sync;
|
||||
}
|
||||
|
||||
impl RequestPartsExt for Parts {
|
||||
fn extract<E>(&mut self) -> BoxFuture<'_, Result<E, E::Rejection>>
|
||||
fn extract<E>(&mut self) -> impl Future<Output = Result<E, E::Rejection>> + Send
|
||||
where
|
||||
E: FromRequestParts<()> + 'static,
|
||||
{
|
||||
@@ -130,7 +125,7 @@ impl RequestPartsExt for Parts {
|
||||
fn extract_with_state<'a, E, S>(
|
||||
&'a mut self,
|
||||
state: &'a S,
|
||||
) -> BoxFuture<'a, Result<E, E::Rejection>>
|
||||
) -> impl Future<Output = Result<E, E::Rejection>> + Send + 'a
|
||||
where
|
||||
E: FromRequestParts<S> + 'static,
|
||||
S: Send + Sync,
|
||||
@@ -148,7 +143,6 @@ mod tests {
|
||||
ext_traits::tests::{RequiresState, State},
|
||||
extract::FromRef,
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use http::{Method, Request};
|
||||
|
||||
#[tokio::test]
|
||||
@@ -181,7 +175,6 @@ mod tests {
|
||||
from_state: String,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequestParts<S> for WorksForCustomExtractor
|
||||
where
|
||||
S: Send + Sync,
|
||||
|
||||
@@ -72,7 +72,7 @@ use tower_layer::Layer;
|
||||
/// [`RequestBodyLimit`]: tower_http::limit::RequestBodyLimit
|
||||
/// [`RequestExt::with_limited_body`]: crate::RequestExt::with_limited_body
|
||||
/// [`RequestExt::into_limited_body`]: crate::RequestExt::into_limited_body
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[must_use]
|
||||
pub struct DefaultBodyLimit {
|
||||
kind: DefaultBodyLimitKind,
|
||||
@@ -116,7 +116,7 @@ impl DefaultBodyLimit {
|
||||
/// [`Bytes`]: bytes::Bytes
|
||||
/// [`Json`]: https://docs.rs/axum/0.7/axum/struct.Json.html
|
||||
/// [`Form`]: https://docs.rs/axum/0.7/axum/struct.Form.html
|
||||
pub fn disable() -> Self {
|
||||
pub const fn disable() -> Self {
|
||||
Self {
|
||||
kind: DefaultBodyLimitKind::Disable,
|
||||
}
|
||||
@@ -149,7 +149,7 @@ impl DefaultBodyLimit {
|
||||
/// [`Bytes::from_request`]: bytes::Bytes
|
||||
/// [`Json`]: https://docs.rs/axum/0.7/axum/struct.Json.html
|
||||
/// [`Form`]: https://docs.rs/axum/0.7/axum/struct.Form.html
|
||||
pub fn max(limit: usize) -> Self {
|
||||
pub const fn max(limit: usize) -> Self {
|
||||
Self {
|
||||
kind: DefaultBodyLimitKind::Limit(limit),
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
//! [`axum::extract`]: https://docs.rs/axum/0.7/axum/extract/index.html
|
||||
|
||||
use crate::{body::Body, response::IntoResponse};
|
||||
use async_trait::async_trait;
|
||||
use http::request::Parts;
|
||||
use std::convert::Infallible;
|
||||
use std::future::Future;
|
||||
|
||||
pub mod rejection;
|
||||
|
||||
@@ -42,9 +42,8 @@ mod private {
|
||||
/// See [`axum::extract`] for more general docs about extractors.
|
||||
///
|
||||
/// [`axum::extract`]: https://docs.rs/axum/0.7/axum/extract/index.html
|
||||
#[async_trait]
|
||||
#[cfg_attr(
|
||||
nightly_error_messages,
|
||||
#[rustversion::attr(
|
||||
since(1.78),
|
||||
diagnostic::on_unimplemented(
|
||||
note = "Function argument is not a valid axum extractor. \nSee `https://docs.rs/axum/0.7/axum/extract/index.html` for details",
|
||||
)
|
||||
@@ -55,7 +54,10 @@ pub trait FromRequestParts<S>: Sized {
|
||||
type Rejection: IntoResponse;
|
||||
|
||||
/// Perform the extraction.
|
||||
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection>;
|
||||
fn from_request_parts(
|
||||
parts: &mut Parts,
|
||||
state: &S,
|
||||
) -> impl Future<Output = Result<Self, Self::Rejection>> + Send;
|
||||
}
|
||||
|
||||
/// Types that can be created from requests.
|
||||
@@ -69,9 +71,8 @@ pub trait FromRequestParts<S>: Sized {
|
||||
/// See [`axum::extract`] for more general docs about extractors.
|
||||
///
|
||||
/// [`axum::extract`]: https://docs.rs/axum/0.7/axum/extract/index.html
|
||||
#[async_trait]
|
||||
#[cfg_attr(
|
||||
nightly_error_messages,
|
||||
#[rustversion::attr(
|
||||
since(1.78),
|
||||
diagnostic::on_unimplemented(
|
||||
note = "Function argument is not a valid axum extractor. \nSee `https://docs.rs/axum/0.7/axum/extract/index.html` for details",
|
||||
)
|
||||
@@ -82,10 +83,12 @@ pub trait FromRequest<S, M = private::ViaRequest>: Sized {
|
||||
type Rejection: IntoResponse;
|
||||
|
||||
/// Perform the extraction.
|
||||
async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection>;
|
||||
fn from_request(
|
||||
req: Request,
|
||||
state: &S,
|
||||
) -> impl Future<Output = Result<Self, Self::Rejection>> + Send;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S, T> FromRequest<S, private::ViaParts> for T
|
||||
where
|
||||
S: Send + Sync,
|
||||
@@ -99,7 +102,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S, T> FromRequestParts<S> for Option<T>
|
||||
where
|
||||
T: FromRequestParts<S>,
|
||||
@@ -115,7 +117,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S, T> FromRequest<S> for Option<T>
|
||||
where
|
||||
T: FromRequest<S>,
|
||||
@@ -128,7 +129,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S, T> FromRequestParts<S> for Result<T, T::Rejection>
|
||||
where
|
||||
T: FromRequestParts<S>,
|
||||
@@ -141,7 +141,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S, T> FromRequest<S> for Result<T, T::Rejection>
|
||||
where
|
||||
T: FromRequest<S>,
|
||||
|
||||
@@ -42,7 +42,7 @@ define_rejection! {
|
||||
#[body = "Failed to buffer the request body"]
|
||||
/// Encountered some other error when buffering the body.
|
||||
///
|
||||
/// This can _only_ happen when you're using [`tower_http::limit::RequestBodyLimitLayer`] or
|
||||
/// This can _only_ happen when you're using [`tower_http::limit::RequestBodyLimitLayer`] or
|
||||
/// otherwise wrapping request bodies in [`http_body_util::Limited`].
|
||||
pub struct LengthLimitError(Error);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
use super::{rejection::*, FromRequest, FromRequestParts, Request};
|
||||
use crate::{body::Body, RequestExt};
|
||||
use async_trait::async_trait;
|
||||
use bytes::Bytes;
|
||||
use bytes::{BufMut, Bytes, BytesMut};
|
||||
use http::{request::Parts, Extensions, HeaderMap, Method, Uri, Version};
|
||||
use http_body_util::BodyExt;
|
||||
use std::convert::Infallible;
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequest<S> for Request
|
||||
where
|
||||
S: Send + Sync,
|
||||
@@ -18,7 +16,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequestParts<S> for Method
|
||||
where
|
||||
S: Send + Sync,
|
||||
@@ -30,7 +27,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequestParts<S> for Uri
|
||||
where
|
||||
S: Send + Sync,
|
||||
@@ -42,7 +38,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequestParts<S> for Version
|
||||
where
|
||||
S: Send + Sync,
|
||||
@@ -59,7 +54,6 @@ where
|
||||
/// Prefer using [`TypedHeader`] to extract only the headers you need.
|
||||
///
|
||||
/// [`TypedHeader`]: https://docs.rs/axum/0.7/axum/extract/struct.TypedHeader.html
|
||||
#[async_trait]
|
||||
impl<S> FromRequestParts<S> for HeaderMap
|
||||
where
|
||||
S: Send + Sync,
|
||||
@@ -71,7 +65,36 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequest<S> for BytesMut
|
||||
where
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = BytesRejection;
|
||||
|
||||
async fn from_request(req: Request, _: &S) -> Result<Self, Self::Rejection> {
|
||||
let mut body = req.into_limited_body();
|
||||
let mut bytes = BytesMut::new();
|
||||
body_to_bytes_mut(&mut body, &mut bytes).await?;
|
||||
Ok(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
async fn body_to_bytes_mut(body: &mut Body, bytes: &mut BytesMut) -> Result<(), BytesRejection> {
|
||||
while let Some(frame) = body
|
||||
.frame()
|
||||
.await
|
||||
.transpose()
|
||||
.map_err(FailedToBufferBody::from_err)?
|
||||
{
|
||||
let Ok(data) = frame.into_data() else {
|
||||
return Ok(());
|
||||
};
|
||||
bytes.put(data);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl<S> FromRequest<S> for Bytes
|
||||
where
|
||||
S: Send + Sync,
|
||||
@@ -90,7 +113,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequest<S> for String
|
||||
where
|
||||
S: Send + Sync,
|
||||
@@ -106,15 +128,12 @@ where
|
||||
}
|
||||
})?;
|
||||
|
||||
let string = std::str::from_utf8(&bytes)
|
||||
.map_err(InvalidUtf8::from_err)?
|
||||
.to_owned();
|
||||
let string = String::from_utf8(bytes.into()).map_err(InvalidUtf8::from_err)?;
|
||||
|
||||
Ok(string)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequestParts<S> for Parts
|
||||
where
|
||||
S: Send + Sync,
|
||||
@@ -126,7 +145,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequestParts<S> for Extensions
|
||||
where
|
||||
S: Send + Sync,
|
||||
@@ -138,7 +156,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequest<S> for Body
|
||||
where
|
||||
S: Send + Sync,
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
use super::{FromRequest, FromRequestParts, Request};
|
||||
use crate::response::{IntoResponse, Response};
|
||||
use async_trait::async_trait;
|
||||
use http::request::Parts;
|
||||
use std::convert::Infallible;
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequestParts<S> for ()
|
||||
where
|
||||
S: Send + Sync,
|
||||
@@ -20,7 +18,6 @@ macro_rules! impl_from_request {
|
||||
(
|
||||
[$($ty:ident),*], $last:ident
|
||||
) => {
|
||||
#[async_trait]
|
||||
#[allow(non_snake_case, unused_mut, unused_variables)]
|
||||
impl<S, $($ty,)* $last> FromRequestParts<S> for ($($ty,)* $last,)
|
||||
where
|
||||
@@ -46,7 +43,6 @@ macro_rules! impl_from_request {
|
||||
|
||||
// This impl must not be generic over M, otherwise it would conflict with the blanket
|
||||
// implementation of `FromRequest<S, Mut>` for `T: FromRequestParts<S>`.
|
||||
#[async_trait]
|
||||
#[allow(non_snake_case, unused_mut, unused_variables)]
|
||||
impl<S, $($ty,)* $last> FromRequest<S> for ($($ty,)* $last,)
|
||||
where
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#![cfg_attr(nightly_error_messages, feature(diagnostic_namespace))]
|
||||
//! Core types and traits for [`axum`].
|
||||
//!
|
||||
//! Libraries authors that want to provide [`FromRequest`] or [`IntoResponse`] implementations
|
||||
@@ -22,7 +21,6 @@
|
||||
clippy::needless_borrow,
|
||||
clippy::match_wildcard_for_single_variants,
|
||||
clippy::if_let_mutex,
|
||||
clippy::mismatched_target_os,
|
||||
clippy::await_holding_lock,
|
||||
clippy::match_on_vec_items,
|
||||
clippy::imprecise_flops,
|
||||
@@ -52,6 +50,11 @@
|
||||
|
||||
#[macro_use]
|
||||
pub(crate) mod macros;
|
||||
#[doc(hidden)] // macro helpers
|
||||
pub mod __private {
|
||||
#[cfg(feature = "tracing")]
|
||||
pub use tracing;
|
||||
}
|
||||
|
||||
mod error;
|
||||
mod ext_traits;
|
||||
|
||||
+15
-6
@@ -1,4 +1,5 @@
|
||||
/// Private API.
|
||||
#[cfg(feature = "tracing")]
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __log_rejection {
|
||||
@@ -7,20 +8,30 @@ macro_rules! __log_rejection {
|
||||
body_text = $body_text:expr,
|
||||
status = $status:expr,
|
||||
) => {
|
||||
#[cfg(feature = "tracing")]
|
||||
{
|
||||
tracing::event!(
|
||||
$crate::__private::tracing::event!(
|
||||
target: "axum::rejection",
|
||||
tracing::Level::TRACE,
|
||||
$crate::__private::tracing::Level::TRACE,
|
||||
status = $status.as_u16(),
|
||||
body = $body_text,
|
||||
rejection_type = std::any::type_name::<$ty>(),
|
||||
rejection_type = ::std::any::type_name::<$ty>(),
|
||||
"rejecting request",
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "tracing"))]
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __log_rejection {
|
||||
(
|
||||
rejection_type = $ty:ident,
|
||||
body_text = $body_text:expr,
|
||||
status = $status:expr,
|
||||
) => {};
|
||||
}
|
||||
|
||||
/// Private API.
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
@@ -303,8 +314,6 @@ mod composite_rejection_tests {
|
||||
|
||||
#[allow(dead_code, unreachable_pub)]
|
||||
mod defs {
|
||||
use crate::{__composite_rejection, __define_rejection};
|
||||
|
||||
__define_rejection! {
|
||||
#[status = BAD_REQUEST]
|
||||
#[body = "error message 1"]
|
||||
|
||||
@@ -29,7 +29,7 @@ use std::fmt;
|
||||
/// )
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[must_use]
|
||||
pub struct AppendHeaders<I>(pub I);
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ use std::{
|
||||
/// MyError::SomethingElseWentWrong => "something else went wrong",
|
||||
/// };
|
||||
///
|
||||
/// // its often easiest to implement `IntoResponse` by calling other implementations
|
||||
/// // it's often easiest to implement `IntoResponse` by calling other implementations
|
||||
/// (StatusCode::INTERNAL_SERVER_ERROR, body).into_response()
|
||||
/// }
|
||||
/// }
|
||||
@@ -113,6 +113,7 @@ use std::{
|
||||
/// ```
|
||||
pub trait IntoResponse {
|
||||
/// Create a response.
|
||||
#[must_use]
|
||||
fn into_response(self) -> Response;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ use std::{convert::Infallible, fmt};
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // Its also recommended to implement `IntoResponse` so `SetHeader` can be used on its own as
|
||||
/// // It's also recommended to implement `IntoResponse` so `SetHeader` can be used on its own as
|
||||
/// // the response
|
||||
/// impl<'a> IntoResponse for SetHeader<'a> {
|
||||
/// fn into_response(self) -> Response {
|
||||
@@ -105,21 +105,25 @@ pub struct ResponseParts {
|
||||
|
||||
impl ResponseParts {
|
||||
/// Gets a reference to the response headers.
|
||||
#[must_use]
|
||||
pub fn headers(&self) -> &HeaderMap {
|
||||
self.res.headers()
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the response headers.
|
||||
#[must_use]
|
||||
pub fn headers_mut(&mut self) -> &mut HeaderMap {
|
||||
self.res.headers_mut()
|
||||
}
|
||||
|
||||
/// Gets a reference to the response extensions.
|
||||
#[must_use]
|
||||
pub fn extensions(&self) -> &Extensions {
|
||||
self.res.extensions()
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the response extensions.
|
||||
#[must_use]
|
||||
pub fn extensions_mut(&mut self) -> &mut Extensions {
|
||||
self.res.extensions_mut()
|
||||
}
|
||||
@@ -260,3 +264,11 @@ impl IntoResponseParts for Extensions {
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResponseParts for () {
|
||||
type Error = Infallible;
|
||||
|
||||
fn into_response_parts(self, res: ResponseParts) -> Result<ResponseParts, Self::Error> {
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +121,7 @@ where
|
||||
///
|
||||
/// See [`Result`] for more details.
|
||||
#[derive(Debug)]
|
||||
#[must_use]
|
||||
pub struct ErrorResponse(Response);
|
||||
|
||||
impl<T> From<T> for ErrorResponse
|
||||
|
||||
Reference in New Issue
Block a user