Import 'axum-core' crate
Request Document: go/android-rust-importing-crates
For CL Reviewers: go/android3p#cl-review
For Build Team: go/ab-third-party-imports
Bug: http://b/339172336
Test: m libaxum_core
Change-Id: I53662b48193283a926bc31431c681068b0c43ba9
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..0f7ae05
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,42 @@
+// This file is generated by cargo_embargo.
+// Do not modify this file after the first "rust_*" or "genrule" module
+// because the changes will be overridden on upgrade.
+// Content before the first "rust_*" or "genrule" module is preserved.
+
+package {
+ default_applicable_licenses: ["external_rust_crates_libaxum_core_license"],
+}
+
+license {
+ name: "external_rust_crates_libaxum_core_license",
+ visibility: [":__subpackages__"],
+ license_kinds: ["SPDX-license-identifier-MIT"],
+ license_text: ["LICENSE"],
+}
+
+rust_library {
+ name: "libaxum_core",
+ host_supported: true,
+ crate_name: "axum_core",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.3.4",
+ crate_root: "src/lib.rs",
+ edition: "2021",
+ cfgs: ["nightly_error_messages"],
+ rustlibs: [
+ "libbytes",
+ "libfutures_util",
+ "libhttp",
+ "libhttp_body",
+ "libmime",
+ "libtower_layer",
+ "libtower_service",
+ ],
+ proc_macros: ["libasync_trait"],
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
+ product_available: true,
+ vendor_available: true,
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..f17c225
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,210 @@
+# Changelog
+
+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
+
+- None.
+
+# 0.3.4 (11. April, 2023)
+
+- Changes to private APIs.
+
+# 0.3.3 (03. March, 2023)
+
+- **fixed:** Add `#[must_use]` attributes to types that do nothing unless used ([#1809])
+
+[#1809]: https://github.com/tokio-rs/axum/pull/1809
+
+# 0.3.2 (20. January, 2023)
+
+- **added:** Implement `IntoResponse` for `&'static [u8; N]` and `[u8; N]` ([#1690])
+
+[#1690]: https://github.com/tokio-rs/axum/pull/1690
+
+# 0.3.1 (9. January, 2023)
+
+- **added:** Add `body_text` and `status` methods to built-in rejections ([#1612])
+
+[#1612]: https://github.com/tokio-rs/axum/pull/1612
+
+# 0.3.0 (25. November, 2022)
+
+- **added:** Added new `FromRequestParts` trait. See axum's changelog for more
+ details ([#1272])
+- **breaking:** `FromRequest` has been reworked and `RequestParts` has been
+ removed. See axum's changelog for more details ([#1272])
+- **breaking:** `BodyAlreadyExtracted` has been removed ([#1272])
+- **breaking:** `AppendHeaders` now works on any `impl IntoIterator` ([#1495])
+
+[#1272]: https://github.com/tokio-rs/axum/pull/1272
+[#1495]: https://github.com/tokio-rs/axum/pull/1495
+
+<details>
+<summary>0.3.0 Pre-Releases</summary>
+
+# 0.3.0-rc.3 (8. November, 2022)
+
+- **added:** Add `DefaultBodyLimit::max` for changing the default body limit ([#1397])
+- **added:** Add `Error::into_inner` for converting `Error` to `BoxError` without allocating ([#1476])
+- **breaking:** `AppendHeaders` now works on any `impl IntoIterator` ([#1495])
+
+[#1397]: https://github.com/tokio-rs/axum/pull/1397
+[#1476]: https://github.com/tokio-rs/axum/pull/1476
+[#1495]: https://github.com/tokio-rs/axum/pull/1495
+
+# 0.3.0-rc.2 (10. September, 2022)
+
+- **breaking:** Added default limit to how much data `Bytes::from_request` will
+ consume. Previously it would attempt to consume the entire request body
+ without checking its length. This meant if a malicious peer sent an large (or
+ infinite) request body your server might run out of memory and crash.
+
+ The default limit is at 2 MB and can be disabled by adding the new
+ `DefaultBodyLimit::disable()` middleware. See its documentation for more
+ details.
+
+ This also applies to `String` which used `Bytes::from_request` internally.
+
+ ([#1346])
+
+[#1346]: https://github.com/tokio-rs/axum/pull/1346
+
+# 0.3.0-rc.1 (23. August, 2022)
+
+- **breaking:** `FromRequest` has been reworked and `RequestParts` has been
+ removed. See axum's changelog for more details ([#1272])
+- **added:** Added new `FromRequestParts` trait. See axum's changelog for more
+ details ([#1272])
+- **breaking:** `BodyAlreadyExtracted` has been removed ([#1272])
+
+[#1155]: https://github.com/tokio-rs/axum/pull/1155
+[#1272]: https://github.com/tokio-rs/axum/pull/1272
+
+</details>
+
+# 0.2.8 (10. September, 2022)
+
+- **breaking:** Added default limit to how much data `Bytes::from_request` will
+ consume. Previously it would attempt to consume the entire request body
+ without checking its length. This meant if a malicious peer sent an large (or
+ infinite) request body your server might run out of memory and crash.
+
+ The default limit is at 2 MB and can be disabled by adding the new
+ `DefaultBodyLimit::disable()` middleware. See its documentation for more
+ details.
+
+ This also applies to `String` which used `Bytes::from_request` internally.
+
+ ([#1346])
+
+[#1346]: https://github.com/tokio-rs/axum/pull/1346
+
+# 0.2.7 (10. July, 2022)
+
+- **fix:** Fix typos in `RequestParts` docs ([#1147])
+
+[#1147]: https://github.com/tokio-rs/axum/pull/1147
+
+# 0.2.6 (18. June, 2022)
+
+- **change:** axum-core's MSRV is now 1.56 ([#1098])
+
+[#1098]: https://github.com/tokio-rs/axum/pull/1098
+
+# 0.2.5 (08. June, 2022)
+
+- **added:** Automatically handle `http_body::LengthLimitError` in `FailedToBufferBody` and map
+ such errors to `413 Payload Too Large` ([#1048])
+- **fixed:** Use `impl IntoResponse` less in docs ([#1049])
+
+[#1048]: https://github.com/tokio-rs/axum/pull/1048
+[#1049]: https://github.com/tokio-rs/axum/pull/1049
+
+# 0.2.4 (02. May, 2022)
+
+- **added:** Implement `IntoResponse` and `IntoResponseParts` for `http::Extensions` ([#975])
+- **added:** Implement `IntoResponse` for `(http::response::Parts, impl IntoResponse)` ([#950])
+- **added:** Implement `IntoResponse` for `(http::response::Response<()>, impl IntoResponse)` ([#950])
+- **added:** Implement `IntoResponse for (Parts | Request<()>, $(impl IntoResponseParts)+, impl IntoResponse)` ([#980])
+
+[#950]: https://github.com/tokio-rs/axum/pull/950
+[#975]: https://github.com/tokio-rs/axum/pull/975
+[#980]: https://github.com/tokio-rs/axum/pull/980
+
+# 0.2.3 (25. April, 2022)
+
+- **added:** Add `response::ErrorResponse` and `response::Result` for
+ `IntoResponse`-based error handling ([#921])
+
+[#921]: https://github.com/tokio-rs/axum/pull/921
+
+# 0.2.2 (19. April, 2022)
+
+- **added:** Add `AppendHeaders` for appending headers to a response rather than overriding them ([#927])
+
+[#927]: https://github.com/tokio-rs/axum/pull/927
+
+# 0.2.1 (03. April, 2022)
+
+- **added:** Add `RequestParts::extract` which allows applying an extractor as a method call ([#897])
+
+[#897]: https://github.com/tokio-rs/axum/pull/897
+
+# 0.2.0 (31. March, 2022)
+
+- **added:** Add `IntoResponseParts` trait which allows defining custom response
+ types for adding headers or extensions to responses ([#797])
+- **breaking:** Using `HeaderMap` as an extractor will no longer remove the headers and thus
+ they'll still be accessible to other extractors, such as `axum::extract::Json`. Instead
+ `HeaderMap` will clone the headers. You should prefer to use `TypedHeader` to extract only the
+ headers you need ([#698])
+
+ This includes these breaking changes:
+ - `RequestParts::take_headers` has been removed.
+ - `RequestParts::headers` returns `&HeaderMap`.
+ - `RequestParts::headers_mut` returns `&mut HeaderMap`.
+ - `HeadersAlreadyExtracted` has been removed.
+ - The `HeadersAlreadyExtracted` variant has been removed from these rejections:
+ - `RequestAlreadyExtracted`
+ - `RequestPartsAlreadyExtracted`
+ - `<HeaderMap as FromRequest<_>>::Rejection` has been changed to `std::convert::Infallible`.
+- **breaking:** `axum::http::Extensions` is no longer an extractor (ie it
+ doesn't implement `FromRequest`). The `axum::extract::Extension` extractor is
+ _not_ impacted by this and works the same. This change makes it harder to
+ accidentally remove all extensions which would result in confusing errors
+ elsewhere ([#699])
+ This includes these breaking changes:
+ - `RequestParts::take_extensions` has been removed.
+ - `RequestParts::extensions` returns `&Extensions`.
+ - `RequestParts::extensions_mut` returns `&mut Extensions`.
+ - `RequestAlreadyExtracted` has been removed.
+ - `<Request as FromRequest>::Rejection` is now `BodyAlreadyExtracted`.
+ - `<http::request::Parts as FromRequest>::Rejection` is now `Infallible`.
+ - `ExtensionsAlreadyExtracted` has been removed.
+- **breaking:** `RequestParts::body_mut` now returns `&mut Option<B>` so the
+ body can be swapped ([#869])
+
+[#698]: https://github.com/tokio-rs/axum/pull/698
+[#699]: https://github.com/tokio-rs/axum/pull/699
+[#797]: https://github.com/tokio-rs/axum/pull/797
+[#869]: https://github.com/tokio-rs/axum/pull/869
+
+# 0.1.2 (22. February, 2022)
+
+- **added:** Implement `IntoResponse` for `bytes::BytesMut` and `bytes::Chain<T, U>` ([#767])
+
+[#767]: https://github.com/tokio-rs/axum/pull/767
+
+# 0.1.1 (06. December, 2021)
+
+- **added:** `axum_core::response::Response` now exists as a shorthand for writing `Response<BoxBody>` ([#590])
+
+[#590]: https://github.com/tokio-rs/axum/pull/590
+
+# 0.1.0 (02. December, 2021)
+
+- Initial release.
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..4d45d91
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,103 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+rust-version = "1.56"
+name = "axum-core"
+version = "0.3.4"
+description = "Core types and traits for axum"
+homepage = "https://github.com/tokio-rs/axum"
+readme = "README.md"
+keywords = [
+ "http",
+ "web",
+ "framework",
+]
+categories = [
+ "asynchronous",
+ "network-programming",
+ "web-programming",
+]
+license = "MIT"
+repository = "https://github.com/tokio-rs/axum"
+
+[package.metadata.cargo-public-api-crates]
+allowed = [
+ "futures_core",
+ "http",
+ "bytes",
+ "http_body",
+ "tower_layer",
+]
+
+[dependencies.async-trait]
+version = "0.1.67"
+
+[dependencies.bytes]
+version = "1.0"
+
+[dependencies.futures-util]
+version = "0.3"
+features = ["alloc"]
+default-features = false
+
+[dependencies.http]
+version = "0.2.7"
+
+[dependencies.http-body]
+version = "0.4.5"
+
+[dependencies.mime]
+version = "0.3.16"
+
+[dependencies.tower-http]
+version = "0.4"
+features = ["limit"]
+optional = true
+
+[dependencies.tower-layer]
+version = "0.3"
+
+[dependencies.tower-service]
+version = "0.3"
+
+[dependencies.tracing]
+version = "0.1.37"
+optional = true
+default-features = false
+
+[dev-dependencies.axum]
+version = "0.6.0"
+features = ["headers"]
+
+[dev-dependencies.futures-util]
+version = "0.3"
+features = ["alloc"]
+default-features = false
+
+[dev-dependencies.hyper]
+version = "0.14.24"
+
+[dev-dependencies.tokio]
+version = "1.25.0"
+features = ["macros"]
+
+[dev-dependencies.tower-http]
+version = "0.4"
+features = ["limit"]
+
+[build-dependencies.rustversion]
+version = "1.0.9"
+
+[features]
+__private_docs = ["dep:tower-http"]
+tracing = ["dep:tracing"]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..4373dad
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,51 @@
+[package]
+categories = ["asynchronous", "network-programming", "web-programming"]
+description = "Core types and traits for axum"
+edition = "2021"
+rust-version = "1.56"
+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.3.4" # remember to also bump the version that axum and axum-extra depend on
+
+[features]
+tracing = ["dep:tracing"]
+
+# Required for intra-doc links to resolve correctly
+__private_docs = ["dep:tower-http"]
+
+[dependencies]
+async-trait = "0.1.67"
+bytes = "1.0"
+futures-util = { version = "0.3", default-features = false, features = ["alloc"] }
+http = "0.2.7"
+http-body = "0.4.5"
+mime = "0.3.16"
+tower-layer = "0.3"
+tower-service = "0.3"
+
+# optional dependencies
+tower-http = { version = "0.4", 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.6.0", features = ["headers"] }
+futures-util = { version = "0.3", default-features = false, features = ["alloc"] }
+hyper = "0.14.24"
+tokio = { version = "1.25.0", features = ["macros"] }
+tower-http = { version = "0.4", features = ["limit"] }
+
+[package.metadata.cargo-public-api-crates]
+allowed = [
+ "futures_core",
+ "http",
+ "bytes",
+ "http_body",
+ "tower_layer",
+]
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..c702b68
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright 2021 Axum Contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+------------------
+
+File: src/body.rs
+
+Copyright (c) 2014-2021 Sean McArthur
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..7933168
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,20 @@
+name: "axum-core"
+description: "Core types and traits for axum"
+third_party {
+ identifier {
+ type: "crates.io"
+ value: "axum-core"
+ }
+ identifier {
+ type: "Archive"
+ value: "https://static.crates.io/crates/axum-core/axum-core-0.3.4.crate"
+ primary_source: true
+ }
+ version: "0.3.4"
+ license_type: NOTICE
+ last_upgrade_date {
+ year: 2024
+ month: 5
+ day: 27
+ }
+}
diff --git a/MODULE_LICENSE_MIT b/MODULE_LICENSE_MIT
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_MIT
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..48bea6e
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 688011
+include platform/prebuilts/rust:main:/OWNERS
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..bd5efbe
--- /dev/null
+++ b/README.md
@@ -0,0 +1,45 @@
+# axum-core
+
+[](https://github.com/tokio-rs/axum-core/actions/workflows/CI.yml)
+[](https://crates.io/crates/axum-core)
+[](https://docs.rs/axum-core)
+
+Core types and traits for axum.
+
+More information about this crate can be found in the [crate documentation][docs].
+
+## Safety
+
+This crate uses `#![forbid(unsafe_code)]` to ensure everything is implemented in 100% safe Rust.
+
+## Minimum supported Rust version
+
+axum-core's MSRV is 1.56.
+
+## Getting Help
+
+You're also welcome to ask in the [Discord channel][chat] or open an [issue]
+with your question.
+
+## Contributing
+
+:balloon: Thanks for your help improving the project! We are so happy to have
+you! We have a [contributing guide][contributing] to help you get involved in the
+`axum` project.
+
+## License
+
+This project is licensed under the [MIT license][license].
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in `axum` by you, shall be licensed as MIT, without any
+additional terms or conditions.
+
+[`axum`]: https://crates.io/crates/axum
+[chat]: https://discord.gg/tokio
+[contributing]: /CONTRIBUTING.md
+[docs]: https://docs.rs/axum-core
+[license]: /axum-core/LICENSE
+[issue]: https://github.com/tokio-rs/axum/issues/new
diff --git a/build.rs b/build.rs
new file mode 100644
index 0000000..b52885c
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,7 @@
+#[rustversion::nightly]
+fn main() {
+ println!("cargo:rustc-cfg=nightly_error_messages");
+}
+
+#[rustversion::not(nightly)]
+fn main() {}
diff --git a/cargo_embargo.json b/cargo_embargo.json
new file mode 100644
index 0000000..6da258a
--- /dev/null
+++ b/cargo_embargo.json
@@ -0,0 +1,3 @@
+{
+ "run_cargo": true
+}
diff --git a/src/body.rs b/src/body.rs
new file mode 100644
index 0000000..9f25408
--- /dev/null
+++ b/src/body.rs
@@ -0,0 +1,92 @@
+//! HTTP body utilities.
+
+use crate::{BoxError, Error};
+use bytes::Bytes;
+use bytes::{Buf, BufMut};
+use http_body::Body;
+
+/// A boxed [`Body`] trait object.
+///
+/// This is used in axum as the response body type for applications. It's
+/// necessary to unify multiple response bodies types into one.
+pub type BoxBody = http_body::combinators::UnsyncBoxBody<Bytes, Error>;
+
+/// Convert a [`http_body::Body`] into a [`BoxBody`].
+pub fn boxed<B>(body: B) -> BoxBody
+where
+ B: http_body::Body<Data = Bytes> + Send + 'static,
+ B::Error: Into<BoxError>,
+{
+ try_downcast(body).unwrap_or_else(|body| body.map_err(Error::new).boxed_unsync())
+}
+
+pub(crate) fn try_downcast<T, K>(k: K) -> Result<T, K>
+where
+ T: 'static,
+ K: Send + 'static,
+{
+ let mut k = Some(k);
+ if let Some(k) = <dyn std::any::Any>::downcast_mut::<Option<T>>(&mut k) {
+ Ok(k.take().unwrap())
+ } else {
+ Err(k.unwrap())
+ }
+}
+
+// copied from hyper under the following license:
+// Copyright (c) 2014-2021 Sean McArthur
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+pub(crate) async fn to_bytes<T>(body: T) -> Result<Bytes, T::Error>
+where
+ T: Body,
+{
+ futures_util::pin_mut!(body);
+
+ // If there's only 1 chunk, we can just return Buf::to_bytes()
+ let mut first = if let Some(buf) = body.data().await {
+ buf?
+ } else {
+ return Ok(Bytes::new());
+ };
+
+ let second = if let Some(buf) = body.data().await {
+ buf?
+ } else {
+ return Ok(first.copy_to_bytes(first.remaining()));
+ };
+
+ // With more than 1 buf, we gotta flatten into a Vec first.
+ let cap = first.remaining() + second.remaining() + body.size_hint().lower() as usize;
+ let mut vec = Vec::with_capacity(cap);
+ vec.put(first);
+ vec.put(second);
+
+ while let Some(buf) = body.data().await {
+ vec.put(buf?);
+ }
+
+ Ok(vec.into())
+}
+
+#[test]
+fn test_try_downcast() {
+ assert_eq!(try_downcast::<i32, _>(5_u32), Err(5_u32));
+ assert_eq!(try_downcast::<i32, _>(5_i32), Ok(5_i32));
+}
diff --git a/src/error.rs b/src/error.rs
new file mode 100644
index 0000000..8c522c7
--- /dev/null
+++ b/src/error.rs
@@ -0,0 +1,34 @@
+use crate::BoxError;
+use std::{error::Error as StdError, fmt};
+
+/// Errors that can happen when using axum.
+#[derive(Debug)]
+pub struct Error {
+ inner: BoxError,
+}
+
+impl Error {
+ /// Create a new `Error` from a boxable error.
+ pub fn new(error: impl Into<BoxError>) -> Self {
+ Self {
+ inner: error.into(),
+ }
+ }
+
+ /// Convert an `Error` back into the underlying boxed trait object.
+ pub fn into_inner(self) -> BoxError {
+ self.inner
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+}
+
+impl StdError for Error {
+ fn source(&self) -> Option<&(dyn StdError + 'static)> {
+ Some(&*self.inner)
+ }
+}
diff --git a/src/ext_traits/mod.rs b/src/ext_traits/mod.rs
new file mode 100644
index 0000000..02595fb
--- /dev/null
+++ b/src/ext_traits/mod.rs
@@ -0,0 +1,50 @@
+pub(crate) mod request;
+pub(crate) mod request_parts;
+
+#[cfg(test)]
+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>,
+ OuterState: Send + Sync,
+ {
+ type Rejection = Infallible;
+
+ async fn from_request_parts(
+ _parts: &mut Parts,
+ state: &OuterState,
+ ) -> Result<Self, Self::Rejection> {
+ let inner_state = InnerState::from_ref(state);
+ Ok(Self(inner_state))
+ }
+ }
+
+ // some extractor that requires the state, such as `SignedCookieJar`
+ pub(crate) struct RequiresState(pub(crate) String);
+
+ #[async_trait]
+ impl<S> FromRequestParts<S> for RequiresState
+ where
+ S: Send + Sync,
+ String: FromRef<S>,
+ {
+ type Rejection = Infallible;
+
+ async fn from_request_parts(
+ _parts: &mut Parts,
+ state: &S,
+ ) -> Result<Self, Self::Rejection> {
+ Ok(Self(String::from_ref(state)))
+ }
+ }
+}
diff --git a/src/ext_traits/request.rs b/src/ext_traits/request.rs
new file mode 100644
index 0000000..e49ba92
--- /dev/null
+++ b/src/ext_traits/request.rs
@@ -0,0 +1,440 @@
+use crate::extract::{DefaultBodyLimitKind, FromRequest, FromRequestParts};
+use futures_util::future::BoxFuture;
+use http::Request;
+use http_body::Limited;
+
+mod sealed {
+ pub trait Sealed<B> {}
+ impl<B> Sealed<B> for http::Request<B> {}
+}
+
+/// Extension trait that adds additional methods to [`Request`].
+pub trait RequestExt<B>: sealed::Sealed<B> + Sized {
+ /// Apply an extractor to this `Request`.
+ ///
+ /// This is just a convenience for `E::from_request(req, &())`.
+ ///
+ /// Note this consumes the request. Use [`RequestExt::extract_parts`] if you're not extracting
+ /// the body and don't want to consume the request.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use axum::{
+ /// async_trait,
+ /// extract::FromRequest,
+ /// http::{header::CONTENT_TYPE, Request, StatusCode},
+ /// response::{IntoResponse, Response},
+ /// Form, Json, RequestExt,
+ /// };
+ ///
+ /// struct FormOrJson<T>(T);
+ ///
+ /// #[async_trait]
+ /// impl<S, B, T> FromRequest<S, B> for FormOrJson<T>
+ /// where
+ /// Json<T>: FromRequest<(), B>,
+ /// Form<T>: FromRequest<(), B>,
+ /// T: 'static,
+ /// B: Send + 'static,
+ /// S: Send + Sync,
+ /// {
+ /// type Rejection = Response;
+ ///
+ /// async fn from_request(req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
+ /// let content_type = req
+ /// .headers()
+ /// .get(CONTENT_TYPE)
+ /// .and_then(|value| value.to_str().ok())
+ /// .ok_or_else(|| StatusCode::BAD_REQUEST.into_response())?;
+ ///
+ /// if content_type.starts_with("application/json") {
+ /// let Json(payload) = req
+ /// .extract::<Json<T>, _>()
+ /// .await
+ /// .map_err(|err| err.into_response())?;
+ ///
+ /// Ok(Self(payload))
+ /// } else if content_type.starts_with("application/x-www-form-urlencoded") {
+ /// let Form(payload) = req
+ /// .extract::<Form<T>, _>()
+ /// .await
+ /// .map_err(|err| err.into_response())?;
+ ///
+ /// Ok(Self(payload))
+ /// } else {
+ /// Err(StatusCode::BAD_REQUEST.into_response())
+ /// }
+ /// }
+ /// }
+ /// ```
+ fn extract<E, M>(self) -> BoxFuture<'static, Result<E, E::Rejection>>
+ where
+ E: FromRequest<(), B, M> + 'static,
+ M: 'static;
+
+ /// Apply an extractor that requires some state to this `Request`.
+ ///
+ /// This is just a convenience for `E::from_request(req, state)`.
+ ///
+ /// Note this consumes the request. Use [`RequestExt::extract_parts_with_state`] if you're not
+ /// extracting the body and don't want to consume the request.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use axum::{
+ /// async_trait,
+ /// extract::{FromRef, FromRequest},
+ /// http::Request,
+ /// RequestExt,
+ /// };
+ ///
+ /// struct MyExtractor {
+ /// requires_state: RequiresState,
+ /// }
+ ///
+ /// #[async_trait]
+ /// impl<S, B> FromRequest<S, B> for MyExtractor
+ /// where
+ /// String: FromRef<S>,
+ /// S: Send + Sync,
+ /// B: Send + 'static,
+ /// {
+ /// type Rejection = std::convert::Infallible;
+ ///
+ /// async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
+ /// let requires_state = req.extract_with_state::<RequiresState, _, _>(state).await?;
+ ///
+ /// Ok(Self { requires_state })
+ /// }
+ /// }
+ ///
+ /// // some extractor that consumes the request body and requires state
+ /// struct RequiresState { /* ... */ }
+ ///
+ /// #[async_trait]
+ /// impl<S, B> FromRequest<S, B> for RequiresState
+ /// where
+ /// String: FromRef<S>,
+ /// S: Send + Sync,
+ /// B: Send + 'static,
+ /// {
+ /// // ...
+ /// # type Rejection = std::convert::Infallible;
+ /// # async fn from_request(req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
+ /// # todo!()
+ /// # }
+ /// }
+ /// ```
+ fn extract_with_state<E, S, M>(self, state: &S) -> BoxFuture<'_, Result<E, E::Rejection>>
+ where
+ E: FromRequest<S, B, M> + 'static,
+ S: Send + Sync;
+
+ /// Apply a parts extractor to this `Request`.
+ ///
+ /// This is just a convenience for `E::from_request_parts(parts, state)`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use axum::{
+ /// async_trait,
+ /// extract::FromRequest,
+ /// headers::{authorization::Bearer, Authorization},
+ /// http::Request,
+ /// response::{IntoResponse, Response},
+ /// Json, RequestExt, TypedHeader,
+ /// };
+ ///
+ /// struct MyExtractor<T> {
+ /// bearer_token: String,
+ /// payload: T,
+ /// }
+ ///
+ /// #[async_trait]
+ /// impl<S, B, T> FromRequest<S, B> for MyExtractor<T>
+ /// where
+ /// B: Send + 'static,
+ /// S: Send + Sync,
+ /// Json<T>: FromRequest<(), B>,
+ /// T: 'static,
+ /// {
+ /// type Rejection = Response;
+ ///
+ /// async fn from_request(mut req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
+ /// let TypedHeader(auth_header) = req
+ /// .extract_parts::<TypedHeader<Authorization<Bearer>>>()
+ /// .await
+ /// .map_err(|err| err.into_response())?;
+ ///
+ /// let Json(payload) = req
+ /// .extract::<Json<T>, _>()
+ /// .await
+ /// .map_err(|err| err.into_response())?;
+ ///
+ /// Ok(Self {
+ /// bearer_token: auth_header.token().to_owned(),
+ /// payload,
+ /// })
+ /// }
+ /// }
+ /// ```
+ fn extract_parts<E>(&mut self) -> BoxFuture<'_, Result<E, E::Rejection>>
+ where
+ E: FromRequestParts<()> + 'static;
+
+ /// Apply a parts extractor that requires some state to this `Request`.
+ ///
+ /// This is just a convenience for `E::from_request_parts(parts, state)`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use axum::{
+ /// async_trait,
+ /// extract::{FromRef, FromRequest, FromRequestParts},
+ /// http::{request::Parts, Request},
+ /// response::{IntoResponse, Response},
+ /// Json, RequestExt,
+ /// };
+ ///
+ /// struct MyExtractor<T> {
+ /// requires_state: RequiresState,
+ /// payload: T,
+ /// }
+ ///
+ /// #[async_trait]
+ /// impl<S, B, T> FromRequest<S, B> for MyExtractor<T>
+ /// where
+ /// String: FromRef<S>,
+ /// Json<T>: FromRequest<(), B>,
+ /// T: 'static,
+ /// S: Send + Sync,
+ /// B: Send + 'static,
+ /// {
+ /// type Rejection = Response;
+ ///
+ /// async fn from_request(mut req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
+ /// let requires_state = req
+ /// .extract_parts_with_state::<RequiresState, _>(state)
+ /// .await
+ /// .map_err(|err| err.into_response())?;
+ ///
+ /// let Json(payload) = req
+ /// .extract::<Json<T>, _>()
+ /// .await
+ /// .map_err(|err| err.into_response())?;
+ ///
+ /// Ok(Self {
+ /// requires_state,
+ /// payload,
+ /// })
+ /// }
+ /// }
+ ///
+ /// struct RequiresState {}
+ ///
+ /// #[async_trait]
+ /// impl<S> FromRequestParts<S> for RequiresState
+ /// where
+ /// String: FromRef<S>,
+ /// S: Send + Sync,
+ /// {
+ /// // ...
+ /// # type Rejection = std::convert::Infallible;
+ /// # async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
+ /// # todo!()
+ /// # }
+ /// }
+ /// ```
+ fn extract_parts_with_state<'a, E, S>(
+ &'a mut self,
+ state: &'a S,
+ ) -> BoxFuture<'a, Result<E, E::Rejection>>
+ where
+ E: FromRequestParts<S> + 'static,
+ S: Send + Sync;
+
+ /// Apply the [default body limit](crate::extract::DefaultBodyLimit).
+ ///
+ /// If it is disabled, return the request as-is in `Err`.
+ fn with_limited_body(self) -> Result<Request<Limited<B>>, Request<B>>;
+
+ /// Consumes the request, returning the body wrapped in [`Limited`] if a
+ /// [default limit](crate::extract::DefaultBodyLimit) is in place, or not wrapped if the
+ /// default limit is disabled.
+ fn into_limited_body(self) -> Result<Limited<B>, B>;
+}
+
+impl<B> RequestExt<B> for Request<B>
+where
+ B: Send + 'static,
+{
+ fn extract<E, M>(self) -> BoxFuture<'static, Result<E, E::Rejection>>
+ where
+ E: FromRequest<(), B, M> + 'static,
+ M: 'static,
+ {
+ self.extract_with_state(&())
+ }
+
+ fn extract_with_state<E, S, M>(self, state: &S) -> BoxFuture<'_, Result<E, E::Rejection>>
+ where
+ E: FromRequest<S, B, M> + 'static,
+ S: Send + Sync,
+ {
+ E::from_request(self, state)
+ }
+
+ fn extract_parts<E>(&mut self) -> BoxFuture<'_, Result<E, E::Rejection>>
+ where
+ E: FromRequestParts<()> + 'static,
+ {
+ self.extract_parts_with_state(&())
+ }
+
+ fn extract_parts_with_state<'a, E, S>(
+ &'a mut self,
+ state: &'a S,
+ ) -> BoxFuture<'a, Result<E, E::Rejection>>
+ where
+ E: FromRequestParts<S> + 'static,
+ S: Send + Sync,
+ {
+ let mut req = Request::new(());
+ *req.version_mut() = self.version();
+ *req.method_mut() = self.method().clone();
+ *req.uri_mut() = self.uri().clone();
+ *req.headers_mut() = std::mem::take(self.headers_mut());
+ *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;
+
+ *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
+ })
+ }
+
+ fn with_limited_body(self) -> Result<Request<Limited<B>>, Request<B>> {
+ // update docs in `axum-core/src/extract/default_body_limit.rs` and
+ // `axum/src/docs/extract.md` if this changes
+ const DEFAULT_LIMIT: usize = 2_097_152; // 2 mb
+
+ match self.extensions().get::<DefaultBodyLimitKind>().copied() {
+ Some(DefaultBodyLimitKind::Disable) => Err(self),
+ Some(DefaultBodyLimitKind::Limit(limit)) => {
+ Ok(self.map(|b| http_body::Limited::new(b, limit)))
+ }
+ None => Ok(self.map(|b| http_body::Limited::new(b, DEFAULT_LIMIT))),
+ }
+ }
+
+ fn into_limited_body(self) -> Result<Limited<B>, B> {
+ self.with_limited_body()
+ .map(Request::into_body)
+ .map_err(Request::into_body)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::{
+ ext_traits::tests::{RequiresState, State},
+ extract::FromRef,
+ };
+ use async_trait::async_trait;
+ use http::Method;
+ use hyper::Body;
+
+ #[tokio::test]
+ async fn extract_without_state() {
+ let req = Request::new(());
+
+ let method: Method = req.extract().await.unwrap();
+
+ assert_eq!(method, Method::GET);
+ }
+
+ #[tokio::test]
+ async fn extract_body_without_state() {
+ let req = Request::new(Body::from("foobar"));
+
+ let body: String = req.extract().await.unwrap();
+
+ assert_eq!(body, "foobar");
+ }
+
+ #[tokio::test]
+ async fn extract_with_state() {
+ let req = Request::new(());
+
+ let state = "state".to_owned();
+
+ let State(extracted_state): State<String> = req.extract_with_state(&state).await.unwrap();
+
+ assert_eq!(extracted_state, state);
+ }
+
+ #[tokio::test]
+ async fn extract_parts_without_state() {
+ let mut req = Request::builder().header("x-foo", "foo").body(()).unwrap();
+
+ let method: Method = req.extract_parts().await.unwrap();
+
+ assert_eq!(method, Method::GET);
+ assert_eq!(req.headers()["x-foo"], "foo");
+ }
+
+ #[tokio::test]
+ async fn extract_parts_with_state() {
+ let mut req = Request::builder().header("x-foo", "foo").body(()).unwrap();
+
+ let state = "state".to_owned();
+
+ let State(extracted_state): State<String> =
+ req.extract_parts_with_state(&state).await.unwrap();
+
+ assert_eq!(extracted_state, state);
+ assert_eq!(req.headers()["x-foo"], "foo");
+ }
+
+ // this stuff just needs to compile
+ #[allow(dead_code)]
+ struct WorksForCustomExtractor {
+ method: Method,
+ from_state: String,
+ body: String,
+ }
+
+ #[async_trait]
+ impl<S, B> FromRequest<S, B> for WorksForCustomExtractor
+ where
+ S: Send + Sync,
+ B: Send + 'static,
+ String: FromRef<S> + FromRequest<(), B>,
+ {
+ type Rejection = <String as FromRequest<(), B>>::Rejection;
+
+ async fn from_request(mut req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
+ let RequiresState(from_state) = req.extract_parts_with_state(state).await.unwrap();
+ let method = req.extract_parts().await.unwrap();
+ let body = req.extract().await?;
+
+ Ok(Self {
+ method,
+ from_state,
+ body,
+ })
+ }
+ }
+}
diff --git a/src/ext_traits/request_parts.rs b/src/ext_traits/request_parts.rs
new file mode 100644
index 0000000..07a7dbf
--- /dev/null
+++ b/src/ext_traits/request_parts.rs
@@ -0,0 +1,200 @@
+use crate::extract::FromRequestParts;
+use futures_util::future::BoxFuture;
+use http::request::Parts;
+
+mod sealed {
+ pub trait Sealed {}
+ impl Sealed for http::request::Parts {}
+}
+
+/// Extension trait that adds additional methods to [`Parts`].
+pub trait RequestPartsExt: sealed::Sealed + Sized {
+ /// Apply an extractor to this `Parts`.
+ ///
+ /// This is just a convenience for `E::from_request_parts(parts, &())`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use axum::{
+ /// extract::{Query, TypedHeader, FromRequestParts},
+ /// response::{Response, IntoResponse},
+ /// headers::UserAgent,
+ /// http::request::Parts,
+ /// RequestPartsExt,
+ /// async_trait,
+ /// };
+ /// use std::collections::HashMap;
+ ///
+ /// struct MyExtractor {
+ /// user_agent: String,
+ /// query_params: HashMap<String, String>,
+ /// }
+ ///
+ /// #[async_trait]
+ /// impl<S> FromRequestParts<S> for MyExtractor
+ /// where
+ /// S: Send + Sync,
+ /// {
+ /// type Rejection = Response;
+ ///
+ /// async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
+ /// let user_agent = parts
+ /// .extract::<TypedHeader<UserAgent>>()
+ /// .await
+ /// .map(|user_agent| user_agent.as_str().to_owned())
+ /// .map_err(|err| err.into_response())?;
+ ///
+ /// let query_params = parts
+ /// .extract::<Query<HashMap<String, String>>>()
+ /// .await
+ /// .map(|Query(params)| params)
+ /// .map_err(|err| err.into_response())?;
+ ///
+ /// Ok(MyExtractor { user_agent, query_params })
+ /// }
+ /// }
+ /// ```
+ fn extract<E>(&mut self) -> BoxFuture<'_, Result<E, E::Rejection>>
+ where
+ E: FromRequestParts<()> + 'static;
+
+ /// Apply an extractor that requires some state to this `Parts`.
+ ///
+ /// This is just a convenience for `E::from_request_parts(parts, state)`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use axum::{
+ /// extract::{FromRef, FromRequestParts},
+ /// 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>,
+ /// S: Send + Sync,
+ /// {
+ /// type Rejection = std::convert::Infallible;
+ ///
+ /// async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
+ /// let requires_state = parts
+ /// .extract_with_state::<RequiresState, _>(state)
+ /// .await?;
+ ///
+ /// Ok(MyExtractor { requires_state })
+ /// }
+ /// }
+ ///
+ /// struct RequiresState { /* ... */ }
+ ///
+ /// // some extractor that requires a `String` in the state
+ /// #[async_trait]
+ /// impl<S> FromRequestParts<S> for RequiresState
+ /// where
+ /// String: FromRef<S>,
+ /// S: Send + Sync,
+ /// {
+ /// // ...
+ /// # type Rejection = std::convert::Infallible;
+ /// # async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
+ /// # unimplemented!()
+ /// # }
+ /// }
+ /// ```
+ fn extract_with_state<'a, E, S>(
+ &'a mut self,
+ state: &'a S,
+ ) -> BoxFuture<'a, Result<E, E::Rejection>>
+ where
+ E: FromRequestParts<S> + 'static,
+ S: Send + Sync;
+}
+
+impl RequestPartsExt for Parts {
+ fn extract<E>(&mut self) -> BoxFuture<'_, Result<E, E::Rejection>>
+ where
+ E: FromRequestParts<()> + 'static,
+ {
+ self.extract_with_state(&())
+ }
+
+ fn extract_with_state<'a, E, S>(
+ &'a mut self,
+ state: &'a S,
+ ) -> BoxFuture<'a, Result<E, E::Rejection>>
+ where
+ E: FromRequestParts<S> + 'static,
+ S: Send + Sync,
+ {
+ E::from_request_parts(self, state)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use std::convert::Infallible;
+
+ use super::*;
+ use crate::{
+ ext_traits::tests::{RequiresState, State},
+ extract::FromRef,
+ };
+ use async_trait::async_trait;
+ use http::{Method, Request};
+
+ #[tokio::test]
+ async fn extract_without_state() {
+ let (mut parts, _) = Request::new(()).into_parts();
+
+ let method: Method = parts.extract().await.unwrap();
+
+ assert_eq!(method, Method::GET);
+ }
+
+ #[tokio::test]
+ async fn extract_with_state() {
+ let (mut parts, _) = Request::new(()).into_parts();
+
+ let state = "state".to_owned();
+
+ let State(extracted_state): State<String> = parts
+ .extract_with_state::<State<String>, String>(&state)
+ .await
+ .unwrap();
+
+ assert_eq!(extracted_state, state);
+ }
+
+ // this stuff just needs to compile
+ #[allow(dead_code)]
+ struct WorksForCustomExtractor {
+ method: Method,
+ from_state: String,
+ }
+
+ #[async_trait]
+ impl<S> FromRequestParts<S> for WorksForCustomExtractor
+ where
+ S: Send + Sync,
+ String: FromRef<S>,
+ {
+ type Rejection = Infallible;
+
+ async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
+ let RequiresState(from_state) = parts.extract_with_state(state).await?;
+ let method = parts.extract().await?;
+
+ Ok(Self { method, from_state })
+ }
+ }
+}
diff --git a/src/extract/default_body_limit.rs b/src/extract/default_body_limit.rs
new file mode 100644
index 0000000..7b37f1e
--- /dev/null
+++ b/src/extract/default_body_limit.rs
@@ -0,0 +1,201 @@
+use self::private::DefaultBodyLimitService;
+use tower_layer::Layer;
+
+/// Layer for configuring the default request body limit.
+///
+/// For security reasons, [`Bytes`] will, by default, not accept bodies larger than 2MB. This also
+/// applies to extractors that uses [`Bytes`] internally such as `String`, [`Json`], and [`Form`].
+///
+/// This middleware provides ways to configure that.
+///
+/// Note that if an extractor consumes the body directly with [`Body::data`], or similar, the
+/// default limit is _not_ applied.
+///
+/// # Difference between `DefaultBodyLimit` and [`RequestBodyLimit`]
+///
+/// `DefaultBodyLimit` and [`RequestBodyLimit`] serve similar functions but in different ways.
+///
+/// `DefaultBodyLimit` is local in that it only applies to [`FromRequest`] implementations that
+/// explicitly apply it (or call another extractor that does). You can apply the limit with
+/// [`RequestExt::with_limited_body`] or [`RequestExt::into_limited_body`]
+///
+/// [`RequestBodyLimit`] is applied globally to all requests, regardless of which extractors are
+/// used or how the body is consumed.
+///
+/// `DefaultBodyLimit` is also easier to integrate into an existing setup since it doesn't change
+/// the request body type:
+///
+/// ```
+/// use axum::{
+/// Router,
+/// routing::post,
+/// body::Body,
+/// extract::{DefaultBodyLimit, RawBody},
+/// http::Request,
+/// };
+///
+/// let app = Router::new()
+/// .route(
+/// "/",
+/// // even with `DefaultBodyLimit` the request body is still just `Body`
+/// post(|request: Request<Body>| async {}),
+/// )
+/// .layer(DefaultBodyLimit::max(1024));
+/// # let _: Router<(), _> = app;
+/// ```
+///
+/// ```
+/// use axum::{Router, routing::post, body::Body, extract::RawBody, http::Request};
+/// use tower_http::limit::RequestBodyLimitLayer;
+/// use http_body::Limited;
+///
+/// let app = Router::new()
+/// .route(
+/// "/",
+/// // `RequestBodyLimitLayer` changes the request body type to `Limited<Body>`
+/// // extracting a different body type wont work
+/// post(|request: Request<Limited<Body>>| async {}),
+/// )
+/// .layer(RequestBodyLimitLayer::new(1024));
+/// # let _: Router<(), _> = app;
+/// ```
+///
+/// In general using `DefaultBodyLimit` is recommended but if you need to use third party
+/// extractors and want to sure a limit is also applied there then [`RequestBodyLimit`] should be
+/// used.
+///
+/// [`Body::data`]: http_body::Body::data
+/// [`Bytes`]: bytes::Bytes
+/// [`Json`]: https://docs.rs/axum/0.6.0/axum/struct.Json.html
+/// [`Form`]: https://docs.rs/axum/0.6.0/axum/struct.Form.html
+/// [`FromRequest`]: crate::extract::FromRequest
+/// [`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)]
+#[must_use]
+pub struct DefaultBodyLimit {
+ kind: DefaultBodyLimitKind,
+}
+
+#[derive(Debug, Clone, Copy)]
+pub(crate) enum DefaultBodyLimitKind {
+ Disable,
+ Limit(usize),
+}
+
+impl DefaultBodyLimit {
+ /// Disable the default request body limit.
+ ///
+ /// This must be used to receive bodies larger than the default limit of 2MB using [`Bytes`] or
+ /// an extractor built on it such as `String`, [`Json`], [`Form`].
+ ///
+ /// Note that if you're accepting data from untrusted remotes it is recommend to add your own
+ /// limit such as [`tower_http::limit`].
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use axum::{
+ /// Router,
+ /// routing::get,
+ /// body::{Bytes, Body},
+ /// extract::DefaultBodyLimit,
+ /// };
+ /// use tower_http::limit::RequestBodyLimitLayer;
+ /// use http_body::Limited;
+ ///
+ /// let app: Router<(), Limited<Body>> = Router::new()
+ /// .route("/", get(|body: Bytes| async {}))
+ /// // Disable the default limit
+ /// .layer(DefaultBodyLimit::disable())
+ /// // Set a different limit
+ /// .layer(RequestBodyLimitLayer::new(10 * 1000 * 1000));
+ /// ```
+ ///
+ /// [`Bytes`]: bytes::Bytes
+ /// [`Json`]: https://docs.rs/axum/0.6.0/axum/struct.Json.html
+ /// [`Form`]: https://docs.rs/axum/0.6.0/axum/struct.Form.html
+ pub fn disable() -> Self {
+ Self {
+ kind: DefaultBodyLimitKind::Disable,
+ }
+ }
+
+ /// Set the default request body limit.
+ ///
+ /// By default the limit of request body sizes that [`Bytes::from_request`] (and other
+ /// extractors built on top of it such as `String`, [`Json`], and [`Form`]) is 2MB. This method
+ /// can be used to change that limit.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use axum::{
+ /// Router,
+ /// routing::get,
+ /// body::{Bytes, Body},
+ /// extract::DefaultBodyLimit,
+ /// };
+ /// use tower_http::limit::RequestBodyLimitLayer;
+ /// use http_body::Limited;
+ ///
+ /// let app: Router<(), Limited<Body>> = Router::new()
+ /// .route("/", get(|body: Bytes| async {}))
+ /// // Replace the default of 2MB with 1024 bytes.
+ /// .layer(DefaultBodyLimit::max(1024));
+ /// ```
+ ///
+ /// [`Bytes::from_request`]: bytes::Bytes
+ /// [`Json`]: https://docs.rs/axum/0.6.0/axum/struct.Json.html
+ /// [`Form`]: https://docs.rs/axum/0.6.0/axum/struct.Form.html
+ pub fn max(limit: usize) -> Self {
+ Self {
+ kind: DefaultBodyLimitKind::Limit(limit),
+ }
+ }
+}
+
+impl<S> Layer<S> for DefaultBodyLimit {
+ type Service = DefaultBodyLimitService<S>;
+
+ fn layer(&self, inner: S) -> Self::Service {
+ DefaultBodyLimitService {
+ inner,
+ kind: self.kind,
+ }
+ }
+}
+
+mod private {
+ use super::DefaultBodyLimitKind;
+ use http::Request;
+ use std::task::Context;
+ use tower_service::Service;
+
+ #[derive(Debug, Clone, Copy)]
+ pub struct DefaultBodyLimitService<S> {
+ pub(super) inner: S,
+ pub(super) kind: DefaultBodyLimitKind,
+ }
+
+ impl<B, S> Service<Request<B>> for DefaultBodyLimitService<S>
+ where
+ S: Service<Request<B>>,
+ {
+ type Response = S::Response;
+ type Error = S::Error;
+ type Future = S::Future;
+
+ #[inline]
+ fn poll_ready(&mut self, cx: &mut Context<'_>) -> std::task::Poll<Result<(), Self::Error>> {
+ self.inner.poll_ready(cx)
+ }
+
+ #[inline]
+ fn call(&mut self, mut req: Request<B>) -> Self::Future {
+ req.extensions_mut().insert(self.kind);
+ self.inner.call(req)
+ }
+ }
+}
diff --git a/src/extract/from_ref.rs b/src/extract/from_ref.rs
new file mode 100644
index 0000000..bdfa7dd
--- /dev/null
+++ b/src/extract/from_ref.rs
@@ -0,0 +1,25 @@
+/// Used to do reference-to-value conversions thus not consuming the input value.
+///
+/// This is mainly used with [`State`] to extract "substates" from a reference to main application
+/// state.
+///
+/// See [`State`] for more details on how library authors should use this trait.
+///
+/// This trait can be derived using `#[derive(FromRef)]`.
+///
+/// [`State`]: https://docs.rs/axum/0.6/axum/extract/struct.State.html
+// NOTE: This trait is defined in axum-core, even though it is mainly used with `State` which is
+// defined in axum. That allows crate authors to use it when implementing extractors.
+pub trait FromRef<T> {
+ /// Converts to this type from a reference to the input type.
+ fn from_ref(input: &T) -> Self;
+}
+
+impl<T> FromRef<T> for T
+where
+ T: Clone,
+{
+ fn from_ref(input: &T) -> Self {
+ input.clone()
+ }
+}
diff --git a/src/extract/mod.rs b/src/extract/mod.rs
new file mode 100644
index 0000000..1113a1e
--- /dev/null
+++ b/src/extract/mod.rs
@@ -0,0 +1,196 @@
+//! Types and traits for extracting data from requests.
+//!
+//! See [`axum::extract`] for more details.
+//!
+//! [`axum::extract`]: https://docs.rs/axum/latest/axum/extract/index.html
+
+use crate::response::IntoResponse;
+use async_trait::async_trait;
+use http::{request::Parts, Request};
+use std::convert::Infallible;
+
+pub mod rejection;
+
+mod default_body_limit;
+mod from_ref;
+mod request_parts;
+mod tuple;
+
+pub(crate) use self::default_body_limit::DefaultBodyLimitKind;
+pub use self::{default_body_limit::DefaultBodyLimit, from_ref::FromRef};
+
+mod private {
+ #[derive(Debug, Clone, Copy)]
+ pub enum ViaParts {}
+
+ #[derive(Debug, Clone, Copy)]
+ pub enum ViaRequest {}
+}
+
+/// Types that can be created from request parts.
+///
+/// Extractors that implement `FromRequestParts` cannot consume the request body and can thus be
+/// run in any order for handlers.
+///
+/// If your extractor needs to consume the request body then you should implement [`FromRequest`]
+/// and not [`FromRequestParts`].
+///
+/// See [`axum::extract`] for more general docs about extractors.
+///
+/// [`axum::extract`]: https://docs.rs/axum/0.6.0/axum/extract/index.html
+#[async_trait]
+#[cfg_attr(
+ nightly_error_messages,
+ rustc_on_unimplemented(
+ note = "Function argument is not a valid axum extractor. \nSee `https://docs.rs/axum/latest/axum/extract/index.html` for details",
+ )
+)]
+pub trait FromRequestParts<S>: Sized {
+ /// If the extractor fails it'll use this "rejection" type. A rejection is
+ /// a kind of error that can be converted into a response.
+ type Rejection: IntoResponse;
+
+ /// Perform the extraction.
+ async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection>;
+}
+
+/// Types that can be created from requests.
+///
+/// Extractors that implement `FromRequest` can consume the request body and can thus only be run
+/// once for handlers.
+///
+/// If your extractor doesn't need to consume the request body then you should implement
+/// [`FromRequestParts`] and not [`FromRequest`].
+///
+/// See [`axum::extract`] for more general docs about extractors.
+///
+/// # What is the `B` type parameter?
+///
+/// `FromRequest` is generic over the request body (the `B` in
+/// [`http::Request<B>`]). This is to allow `FromRequest` to be usable with any
+/// type of request body. This is necessary because some middleware change the
+/// request body, for example to add timeouts.
+///
+/// If you're writing your own `FromRequest` that wont be used outside your
+/// application, and not using any middleware that changes the request body, you
+/// can most likely use `axum::body::Body`.
+///
+/// If you're writing a library that's intended for others to use, it's recommended
+/// to keep the generic type parameter:
+///
+/// ```rust
+/// use axum::{
+/// async_trait,
+/// extract::FromRequest,
+/// http::{self, Request},
+/// };
+///
+/// struct MyExtractor;
+///
+/// #[async_trait]
+/// impl<S, B> FromRequest<S, B> for MyExtractor
+/// where
+/// // these bounds are required by `async_trait`
+/// B: Send + 'static,
+/// S: Send + Sync,
+/// {
+/// type Rejection = http::StatusCode;
+///
+/// async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
+/// // ...
+/// # unimplemented!()
+/// }
+/// }
+/// ```
+///
+/// This ensures your extractor is as flexible as possible.
+///
+/// [`http::Request<B>`]: http::Request
+/// [`axum::extract`]: https://docs.rs/axum/0.6.0/axum/extract/index.html
+#[async_trait]
+#[cfg_attr(
+ nightly_error_messages,
+ rustc_on_unimplemented(
+ note = "Function argument is not a valid axum extractor. \nSee `https://docs.rs/axum/latest/axum/extract/index.html` for details",
+ )
+)]
+pub trait FromRequest<S, B, M = private::ViaRequest>: Sized {
+ /// If the extractor fails it'll use this "rejection" type. A rejection is
+ /// a kind of error that can be converted into a response.
+ type Rejection: IntoResponse;
+
+ /// Perform the extraction.
+ async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection>;
+}
+
+#[async_trait]
+impl<S, B, T> FromRequest<S, B, private::ViaParts> for T
+where
+ B: Send + 'static,
+ S: Send + Sync,
+ T: FromRequestParts<S>,
+{
+ type Rejection = <Self as FromRequestParts<S>>::Rejection;
+
+ async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
+ let (mut parts, _) = req.into_parts();
+ Self::from_request_parts(&mut parts, state).await
+ }
+}
+
+#[async_trait]
+impl<S, T> FromRequestParts<S> for Option<T>
+where
+ T: FromRequestParts<S>,
+ S: Send + Sync,
+{
+ type Rejection = Infallible;
+
+ async fn from_request_parts(
+ parts: &mut Parts,
+ state: &S,
+ ) -> Result<Option<T>, Self::Rejection> {
+ Ok(T::from_request_parts(parts, state).await.ok())
+ }
+}
+
+#[async_trait]
+impl<S, T, B> FromRequest<S, B> for Option<T>
+where
+ T: FromRequest<S, B>,
+ B: Send + 'static,
+ S: Send + Sync,
+{
+ type Rejection = Infallible;
+
+ async fn from_request(req: Request<B>, state: &S) -> Result<Option<T>, Self::Rejection> {
+ Ok(T::from_request(req, state).await.ok())
+ }
+}
+
+#[async_trait]
+impl<S, T> FromRequestParts<S> for Result<T, T::Rejection>
+where
+ T: FromRequestParts<S>,
+ S: Send + Sync,
+{
+ type Rejection = Infallible;
+
+ async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
+ Ok(T::from_request_parts(parts, state).await)
+ }
+}
+
+#[async_trait]
+impl<S, T, B> FromRequest<S, B> for Result<T, T::Rejection>
+where
+ T: FromRequest<S, B>,
+ B: Send + 'static,
+ S: Send + Sync,
+{
+ type Rejection = Infallible;
+
+ async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
+ Ok(T::from_request(req, state).await)
+ }
+}
diff --git a/src/extract/rejection.rs b/src/extract/rejection.rs
new file mode 100644
index 0000000..958f3b2
--- /dev/null
+++ b/src/extract/rejection.rs
@@ -0,0 +1,72 @@
+//! Rejection response types.
+
+use crate::__composite_rejection as composite_rejection;
+use crate::__define_rejection as define_rejection;
+
+use crate::BoxError;
+
+composite_rejection! {
+ /// Rejection type for extractors that buffer the request body. Used if the
+ /// request body cannot be buffered due to an error.
+ pub enum FailedToBufferBody {
+ LengthLimitError,
+ UnknownBodyError,
+ }
+}
+
+impl FailedToBufferBody {
+ pub(crate) fn from_err<E>(err: E) -> Self
+ where
+ E: Into<BoxError>,
+ {
+ match err.into().downcast::<http_body::LengthLimitError>() {
+ Ok(err) => Self::LengthLimitError(LengthLimitError::from_err(err)),
+ Err(err) => Self::UnknownBodyError(UnknownBodyError::from_err(err)),
+ }
+ }
+}
+
+define_rejection! {
+ #[status = PAYLOAD_TOO_LARGE]
+ #[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
+ /// otherwise wrapping request bodies in [`http_body::Limited`].
+ pub struct LengthLimitError(Error);
+}
+
+define_rejection! {
+ #[status = BAD_REQUEST]
+ #[body = "Failed to buffer the request body"]
+ /// Encountered an unknown error when buffering the body.
+ pub struct UnknownBodyError(Error);
+}
+
+define_rejection! {
+ #[status = BAD_REQUEST]
+ #[body = "Request body didn't contain valid UTF-8"]
+ /// Rejection type used when buffering the request into a [`String`] if the
+ /// body doesn't contain valid UTF-8.
+ pub struct InvalidUtf8(Error);
+}
+
+composite_rejection! {
+ /// Rejection used for [`Bytes`](bytes::Bytes).
+ ///
+ /// Contains one variant for each way the [`Bytes`](bytes::Bytes) extractor
+ /// can fail.
+ pub enum BytesRejection {
+ FailedToBufferBody,
+ }
+}
+
+composite_rejection! {
+ /// Rejection used for [`String`].
+ ///
+ /// Contains one variant for each way the [`String`] extractor can fail.
+ pub enum StringRejection {
+ FailedToBufferBody,
+ InvalidUtf8,
+ }
+}
diff --git a/src/extract/request_parts.rs b/src/extract/request_parts.rs
new file mode 100644
index 0000000..05d7d72
--- /dev/null
+++ b/src/extract/request_parts.rs
@@ -0,0 +1,136 @@
+use super::{rejection::*, FromRequest, FromRequestParts};
+use crate::{BoxError, RequestExt};
+use async_trait::async_trait;
+use bytes::Bytes;
+use http::{request::Parts, HeaderMap, Method, Request, Uri, Version};
+use std::convert::Infallible;
+
+#[async_trait]
+impl<S, B> FromRequest<S, B> for Request<B>
+where
+ B: Send,
+ S: Send + Sync,
+{
+ type Rejection = Infallible;
+
+ async fn from_request(req: Request<B>, _: &S) -> Result<Self, Self::Rejection> {
+ Ok(req)
+ }
+}
+
+#[async_trait]
+impl<S> FromRequestParts<S> for Method
+where
+ S: Send + Sync,
+{
+ type Rejection = Infallible;
+
+ async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
+ Ok(parts.method.clone())
+ }
+}
+
+#[async_trait]
+impl<S> FromRequestParts<S> for Uri
+where
+ S: Send + Sync,
+{
+ type Rejection = Infallible;
+
+ async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
+ Ok(parts.uri.clone())
+ }
+}
+
+#[async_trait]
+impl<S> FromRequestParts<S> for Version
+where
+ S: Send + Sync,
+{
+ type Rejection = Infallible;
+
+ async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
+ Ok(parts.version)
+ }
+}
+
+/// Clone the headers from the request.
+///
+/// Prefer using [`TypedHeader`] to extract only the headers you need.
+///
+/// [`TypedHeader`]: https://docs.rs/axum/latest/axum/extract/struct.TypedHeader.html
+#[async_trait]
+impl<S> FromRequestParts<S> for HeaderMap
+where
+ S: Send + Sync,
+{
+ type Rejection = Infallible;
+
+ async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
+ Ok(parts.headers.clone())
+ }
+}
+
+#[async_trait]
+impl<S, B> FromRequest<S, B> for Bytes
+where
+ B: http_body::Body + Send + 'static,
+ B::Data: Send,
+ B::Error: Into<BoxError>,
+ S: Send + Sync,
+{
+ type Rejection = BytesRejection;
+
+ async fn from_request(req: Request<B>, _: &S) -> Result<Self, Self::Rejection> {
+ let bytes = match req.into_limited_body() {
+ Ok(limited_body) => crate::body::to_bytes(limited_body)
+ .await
+ .map_err(FailedToBufferBody::from_err)?,
+ Err(unlimited_body) => crate::body::to_bytes(unlimited_body)
+ .await
+ .map_err(FailedToBufferBody::from_err)?,
+ };
+
+ Ok(bytes)
+ }
+}
+
+#[async_trait]
+impl<S, B> FromRequest<S, B> for String
+where
+ B: http_body::Body + Send + 'static,
+ B::Data: Send,
+ B::Error: Into<BoxError>,
+ S: Send + Sync,
+{
+ type Rejection = StringRejection;
+
+ async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
+ let bytes = Bytes::from_request(req, state)
+ .await
+ .map_err(|err| match err {
+ BytesRejection::FailedToBufferBody(inner) => {
+ StringRejection::FailedToBufferBody(inner)
+ }
+ })?;
+
+ let string = std::str::from_utf8(&bytes)
+ .map_err(InvalidUtf8::from_err)?
+ .to_owned();
+
+ Ok(string)
+ }
+}
+
+#[async_trait]
+impl<S, B> FromRequest<S, B> for Parts
+where
+ B: Send + 'static,
+ S: Send + Sync,
+{
+ type Rejection = Infallible;
+
+ async fn from_request(req: Request<B>, _: &S) -> Result<Self, Self::Rejection> {
+ Ok(req.into_parts().0)
+ }
+}
diff --git a/src/extract/tuple.rs b/src/extract/tuple.rs
new file mode 100644
index 0000000..728135b
--- /dev/null
+++ b/src/extract/tuple.rs
@@ -0,0 +1,119 @@
+use super::{FromRequest, FromRequestParts};
+use crate::response::{IntoResponse, Response};
+use async_trait::async_trait;
+use http::request::{Parts, Request};
+use std::convert::Infallible;
+
+#[async_trait]
+impl<S> FromRequestParts<S> for ()
+where
+ S: Send + Sync,
+{
+ type Rejection = Infallible;
+
+ async fn from_request_parts(_: &mut Parts, _: &S) -> Result<(), Self::Rejection> {
+ Ok(())
+ }
+}
+
+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
+ $( $ty: FromRequestParts<S> + Send, )*
+ $last: FromRequestParts<S> + Send,
+ S: Send + Sync,
+ {
+ type Rejection = Response;
+
+ async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
+ $(
+ let $ty = $ty::from_request_parts(parts, state)
+ .await
+ .map_err(|err| err.into_response())?;
+ )*
+ let $last = $last::from_request_parts(parts, state)
+ .await
+ .map_err(|err| err.into_response())?;
+
+ Ok(($($ty,)* $last,))
+ }
+ }
+
+ // This impl must not be generic over M, otherwise it would conflict with the blanket
+ // implementation of `FromRequest<S, B, Mut>` for `T: FromRequestParts<S>`.
+ #[async_trait]
+ #[allow(non_snake_case, unused_mut, unused_variables)]
+ impl<S, B, $($ty,)* $last> FromRequest<S, B> for ($($ty,)* $last,)
+ where
+ $( $ty: FromRequestParts<S> + Send, )*
+ $last: FromRequest<S, B> + Send,
+ B: Send + 'static,
+ S: Send + Sync,
+ {
+ type Rejection = Response;
+
+ async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
+ let (mut parts, body) = req.into_parts();
+
+ $(
+ let $ty = $ty::from_request_parts(&mut parts, state).await.map_err(|err| err.into_response())?;
+ )*
+
+ let req = Request::from_parts(parts, body);
+
+ let $last = $last::from_request(req, state).await.map_err(|err| err.into_response())?;
+
+ Ok(($($ty,)* $last,))
+ }
+ }
+ };
+}
+
+all_the_tuples!(impl_from_request);
+
+#[cfg(test)]
+mod tests {
+ use bytes::Bytes;
+ use http::Method;
+
+ use crate::extract::{FromRequest, FromRequestParts};
+
+ fn assert_from_request<M, T>()
+ where
+ T: FromRequest<(), http_body::Full<Bytes>, M>,
+ {
+ }
+
+ fn assert_from_request_parts<T: FromRequestParts<()>>() {}
+
+ #[test]
+ fn unit() {
+ assert_from_request_parts::<()>();
+ assert_from_request::<_, ()>();
+ }
+
+ #[test]
+ fn tuple_of_one() {
+ assert_from_request_parts::<(Method,)>();
+ assert_from_request::<_, (Method,)>();
+ assert_from_request::<_, (Bytes,)>();
+ }
+
+ #[test]
+ fn tuple_of_two() {
+ assert_from_request_parts::<((), ())>();
+ assert_from_request::<_, ((), ())>();
+ assert_from_request::<_, (Method, Bytes)>();
+ }
+
+ #[test]
+ fn nested_tuple() {
+ assert_from_request_parts::<(((Method,),),)>();
+ assert_from_request::<_, ((((Bytes,),),),)>();
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..974e5e1
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,66 @@
+#![cfg_attr(nightly_error_messages, feature(rustc_attrs))]
+//! Core types and traits for [`axum`].
+//!
+//! Libraries authors that want to provide [`FromRequest`] or [`IntoResponse`] implementations
+//! should depend on the [`axum-core`] crate, instead of `axum` if possible.
+//!
+//! [`FromRequest`]: crate::extract::FromRequest
+//! [`IntoResponse`]: crate::response::IntoResponse
+//! [`axum`]: https://crates.io/crates/axum
+//! [`axum-core`]: http://crates.io/crates/axum-core
+
+#![warn(
+ clippy::all,
+ clippy::dbg_macro,
+ clippy::todo,
+ clippy::empty_enum,
+ clippy::enum_glob_use,
+ clippy::mem_forget,
+ clippy::unused_self,
+ clippy::filter_map_next,
+ clippy::needless_continue,
+ 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,
+ clippy::suboptimal_flops,
+ clippy::lossy_float_literal,
+ clippy::rest_pat_in_fully_bound_structs,
+ clippy::fn_params_excessive_bools,
+ clippy::exit,
+ clippy::inefficient_to_string,
+ clippy::linkedlist,
+ clippy::macro_use_imports,
+ clippy::option_option,
+ clippy::verbose_file_reads,
+ clippy::unnested_or_patterns,
+ clippy::str_to_string,
+ rust_2018_idioms,
+ future_incompatible,
+ nonstandard_style,
+ missing_debug_implementations,
+ missing_docs
+)]
+#![deny(unreachable_pub, private_in_public)]
+#![allow(elided_lifetimes_in_paths, clippy::type_complexity)]
+#![forbid(unsafe_code)]
+#![cfg_attr(test, allow(clippy::float_cmp))]
+
+#[macro_use]
+pub(crate) mod macros;
+
+mod error;
+mod ext_traits;
+pub use self::error::Error;
+
+pub mod body;
+pub mod extract;
+pub mod response;
+
+/// Alias for a type-erased error type.
+pub type BoxError = Box<dyn std::error::Error + Send + Sync>;
+
+pub use self::ext_traits::{request::RequestExt, request_parts::RequestPartsExt};
diff --git a/src/macros.rs b/src/macros.rs
new file mode 100644
index 0000000..10365e1
--- /dev/null
+++ b/src/macros.rs
@@ -0,0 +1,296 @@
+/// Private API.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! __log_rejection {
+ (
+ rejection_type = $ty:ident,
+ body_text = $body_text:expr,
+ status = $status:expr,
+ ) => {
+ #[cfg(feature = "tracing")]
+ {
+ tracing::event!(
+ target: "axum::rejection",
+ tracing::Level::TRACE,
+ status = $status.as_u16(),
+ body = $body_text,
+ rejection_type = std::any::type_name::<$ty>(),
+ "rejecting request",
+ );
+ }
+ };
+}
+
+/// Private API.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! __define_rejection {
+ (
+ #[status = $status:ident]
+ #[body = $body:expr]
+ $(#[$m:meta])*
+ pub struct $name:ident;
+ ) => {
+ $(#[$m])*
+ #[derive(Debug)]
+ #[non_exhaustive]
+ pub struct $name;
+
+ impl $crate::response::IntoResponse for $name {
+ fn into_response(self) -> $crate::response::Response {
+ $crate::__log_rejection!(
+ rejection_type = $name,
+ body_text = $body,
+ status = http::StatusCode::$status,
+ );
+ (self.status(), $body).into_response()
+ }
+ }
+
+ impl $name {
+ /// Get the response body text used for this rejection.
+ pub fn body_text(&self) -> String {
+ $body.into()
+ }
+
+ /// Get the status code used for this rejection.
+ pub fn status(&self) -> http::StatusCode {
+ http::StatusCode::$status
+ }
+ }
+
+ impl std::fmt::Display for $name {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", $body)
+ }
+ }
+
+ impl std::error::Error for $name {}
+
+ impl Default for $name {
+ fn default() -> Self {
+ Self
+ }
+ }
+ };
+
+ (
+ #[status = $status:ident]
+ #[body = $body:expr]
+ $(#[$m:meta])*
+ pub struct $name:ident (Error);
+ ) => {
+ $(#[$m])*
+ #[derive(Debug)]
+ pub struct $name(pub(crate) $crate::Error);
+
+ impl $name {
+ pub(crate) fn from_err<E>(err: E) -> Self
+ where
+ E: Into<$crate::BoxError>,
+ {
+ Self($crate::Error::new(err))
+ }
+ }
+
+ impl $crate::response::IntoResponse for $name {
+ fn into_response(self) -> $crate::response::Response {
+ $crate::__log_rejection!(
+ rejection_type = $name,
+ body_text = self.body_text(),
+ status = http::StatusCode::$status,
+ );
+ (self.status(), self.body_text()).into_response()
+ }
+ }
+
+ impl $name {
+ /// Get the response body text used for this rejection.
+ pub fn body_text(&self) -> String {
+ format!(concat!($body, ": {}"), self.0).into()
+ }
+
+ /// Get the status code used for this rejection.
+ pub fn status(&self) -> http::StatusCode {
+ http::StatusCode::$status
+ }
+ }
+
+ impl std::fmt::Display for $name {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", $body)
+ }
+ }
+
+ impl std::error::Error for $name {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ Some(&self.0)
+ }
+ }
+ };
+}
+
+/// Private API.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! __composite_rejection {
+ (
+ $(#[$m:meta])*
+ pub enum $name:ident {
+ $($variant:ident),+
+ $(,)?
+ }
+ ) => {
+ $(#[$m])*
+ #[derive(Debug)]
+ #[non_exhaustive]
+ pub enum $name {
+ $(
+ #[allow(missing_docs)]
+ $variant($variant)
+ ),+
+ }
+
+ impl $crate::response::IntoResponse for $name {
+ fn into_response(self) -> $crate::response::Response {
+ match self {
+ $(
+ Self::$variant(inner) => inner.into_response(),
+ )+
+ }
+ }
+ }
+
+ impl $name {
+ /// Get the response body text used for this rejection.
+ pub fn body_text(&self) -> String {
+ match self {
+ $(
+ Self::$variant(inner) => inner.body_text(),
+ )+
+ }
+ }
+
+ /// Get the status code used for this rejection.
+ pub fn status(&self) -> http::StatusCode {
+ match self {
+ $(
+ Self::$variant(inner) => inner.status(),
+ )+
+ }
+ }
+ }
+
+ $(
+ impl From<$variant> for $name {
+ fn from(inner: $variant) -> Self {
+ Self::$variant(inner)
+ }
+ }
+ )+
+
+ impl std::fmt::Display for $name {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ $(
+ Self::$variant(inner) => write!(f, "{}", inner),
+ )+
+ }
+ }
+ }
+
+ impl std::error::Error for $name {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ $(
+ Self::$variant(inner) => Some(inner),
+ )+
+ }
+ }
+ }
+ };
+}
+
+#[rustfmt::skip]
+macro_rules! all_the_tuples {
+ ($name:ident) => {
+ $name!([], T1);
+ $name!([T1], T2);
+ $name!([T1, T2], T3);
+ $name!([T1, T2, T3], T4);
+ $name!([T1, T2, T3, T4], T5);
+ $name!([T1, T2, T3, T4, T5], T6);
+ $name!([T1, T2, T3, T4, T5, T6], T7);
+ $name!([T1, T2, T3, T4, T5, T6, T7], T8);
+ $name!([T1, T2, T3, T4, T5, T6, T7, T8], T9);
+ $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9], T10);
+ $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], T11);
+ $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], T12);
+ $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], T13);
+ $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], T14);
+ $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], T15);
+ $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], T16);
+ };
+}
+
+macro_rules! all_the_tuples_no_last_special_case {
+ ($name:ident) => {
+ $name!(T1);
+ $name!(T1, T2);
+ $name!(T1, T2, T3);
+ $name!(T1, T2, T3, T4);
+ $name!(T1, T2, T3, T4, T5);
+ $name!(T1, T2, T3, T4, T5, T6);
+ $name!(T1, T2, T3, T4, T5, T6, T7);
+ $name!(T1, T2, T3, T4, T5, T6, T7, T8);
+ $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9);
+ $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
+ $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
+ $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
+ $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
+ $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
+ $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15);
+ $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16);
+ };
+}
+
+/// Private API.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! __impl_deref {
+ ($ident:ident) => {
+ impl<T> std::ops::Deref for $ident<T> {
+ type Target = T;
+
+ #[inline]
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+
+ impl<T> std::ops::DerefMut for $ident<T> {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+ }
+ };
+
+ ($ident:ident: $ty:ty) => {
+ impl std::ops::Deref for $ident {
+ type Target = $ty;
+
+ #[inline]
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+
+ impl std::ops::DerefMut for $ident {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+ }
+ };
+}
diff --git a/src/response/append_headers.rs b/src/response/append_headers.rs
new file mode 100644
index 0000000..e4ac481
--- /dev/null
+++ b/src/response/append_headers.rs
@@ -0,0 +1,68 @@
+use super::{IntoResponse, IntoResponseParts, Response, ResponseParts, TryIntoHeaderError};
+use http::header::{HeaderName, HeaderValue};
+use std::fmt;
+
+/// Append headers to a response.
+///
+/// Returning something like `[("content-type", "foo=bar")]` from a handler will override any
+/// existing `content-type` headers. If instead you want to append headers, use `AppendHeaders`:
+///
+/// ```rust
+/// use axum::{
+/// response::{AppendHeaders, IntoResponse},
+/// http::header::SET_COOKIE,
+/// };
+///
+/// async fn handler() -> impl IntoResponse {
+/// // something that sets the `set-cookie` header
+/// let set_some_cookies = /* ... */
+/// # axum::http::HeaderMap::new();
+///
+/// (
+/// set_some_cookies,
+/// // append two `set-cookie` headers to the response
+/// // without overriding the ones added by `set_some_cookies`
+/// AppendHeaders([
+/// (SET_COOKIE, "foo=bar"),
+/// (SET_COOKIE, "baz=qux"),
+/// ])
+/// )
+/// }
+/// ```
+#[derive(Debug)]
+#[must_use]
+pub struct AppendHeaders<I>(pub I);
+
+impl<I, K, V> IntoResponse for AppendHeaders<I>
+where
+ I: IntoIterator<Item = (K, V)>,
+ K: TryInto<HeaderName>,
+ K::Error: fmt::Display,
+ V: TryInto<HeaderValue>,
+ V::Error: fmt::Display,
+{
+ fn into_response(self) -> Response {
+ (self, ()).into_response()
+ }
+}
+
+impl<I, K, V> IntoResponseParts for AppendHeaders<I>
+where
+ I: IntoIterator<Item = (K, V)>,
+ K: TryInto<HeaderName>,
+ K::Error: fmt::Display,
+ V: TryInto<HeaderValue>,
+ V::Error: fmt::Display,
+{
+ type Error = TryIntoHeaderError<K::Error, V::Error>;
+
+ fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
+ for (key, value) in self.0 {
+ let key = key.try_into().map_err(TryIntoHeaderError::key)?;
+ let value = value.try_into().map_err(TryIntoHeaderError::value)?;
+ res.headers_mut().append(key, value);
+ }
+
+ Ok(res)
+ }
+}
diff --git a/src/response/into_response.rs b/src/response/into_response.rs
new file mode 100644
index 0000000..f19974c
--- /dev/null
+++ b/src/response/into_response.rs
@@ -0,0 +1,531 @@
+use super::{IntoResponseParts, Response, ResponseParts};
+use crate::{body, BoxError};
+use bytes::{buf::Chain, Buf, Bytes, BytesMut};
+use http::{
+ header::{self, HeaderMap, HeaderName, HeaderValue},
+ Extensions, StatusCode,
+};
+use http_body::{
+ combinators::{MapData, MapErr},
+ Empty, Full, SizeHint,
+};
+use std::{
+ borrow::Cow,
+ convert::Infallible,
+ fmt,
+ pin::Pin,
+ task::{Context, Poll},
+};
+
+/// Trait for generating responses.
+///
+/// Types that implement `IntoResponse` can be returned from handlers.
+///
+/// # Implementing `IntoResponse`
+///
+/// You generally shouldn't have to implement `IntoResponse` manually, as axum
+/// provides implementations for many common types.
+///
+/// However it might be necessary if you have a custom error type that you want
+/// to return from handlers:
+///
+/// ```rust
+/// use axum::{
+/// Router,
+/// body::{self, Bytes},
+/// routing::get,
+/// http::StatusCode,
+/// response::{IntoResponse, Response},
+/// };
+///
+/// enum MyError {
+/// SomethingWentWrong,
+/// SomethingElseWentWrong,
+/// }
+///
+/// impl IntoResponse for MyError {
+/// fn into_response(self) -> Response {
+/// let body = match self {
+/// MyError::SomethingWentWrong => "something went wrong",
+/// MyError::SomethingElseWentWrong => "something else went wrong",
+/// };
+///
+/// // its often easiest to implement `IntoResponse` by calling other implementations
+/// (StatusCode::INTERNAL_SERVER_ERROR, body).into_response()
+/// }
+/// }
+///
+/// // `Result<impl IntoResponse, MyError>` can now be returned from handlers
+/// let app = Router::new().route("/", get(handler));
+///
+/// async fn handler() -> Result<(), MyError> {
+/// Err(MyError::SomethingWentWrong)
+/// }
+/// # async {
+/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
+/// # };
+/// ```
+///
+/// Or if you have a custom body type you'll also need to implement
+/// `IntoResponse` for it:
+///
+/// ```rust
+/// use axum::{
+/// body,
+/// routing::get,
+/// response::{IntoResponse, Response},
+/// Router,
+/// };
+/// use http_body::Body;
+/// use http::HeaderMap;
+/// use bytes::Bytes;
+/// use std::{
+/// convert::Infallible,
+/// task::{Poll, Context},
+/// pin::Pin,
+/// };
+///
+/// struct MyBody;
+///
+/// // First implement `Body` for `MyBody`. This could for example use
+/// // some custom streaming protocol.
+/// impl Body for MyBody {
+/// type Data = Bytes;
+/// type Error = Infallible;
+///
+/// fn poll_data(
+/// self: Pin<&mut Self>,
+/// cx: &mut Context<'_>
+/// ) -> Poll<Option<Result<Self::Data, Self::Error>>> {
+/// # unimplemented!()
+/// // ...
+/// }
+///
+/// fn poll_trailers(
+/// self: Pin<&mut Self>,
+/// cx: &mut Context<'_>
+/// ) -> Poll<Result<Option<HeaderMap>, Self::Error>> {
+/// # unimplemented!()
+/// // ...
+/// }
+/// }
+///
+/// // Now we can implement `IntoResponse` directly for `MyBody`
+/// impl IntoResponse for MyBody {
+/// fn into_response(self) -> Response {
+/// Response::new(body::boxed(self))
+/// }
+/// }
+///
+/// // `MyBody` can now be returned from handlers.
+/// let app = Router::new().route("/", get(|| async { MyBody }));
+/// # async {
+/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
+/// # };
+/// ```
+pub trait IntoResponse {
+ /// Create a response.
+ fn into_response(self) -> Response;
+}
+
+impl IntoResponse for StatusCode {
+ fn into_response(self) -> Response {
+ let mut res = ().into_response();
+ *res.status_mut() = self;
+ res
+ }
+}
+
+impl IntoResponse for () {
+ fn into_response(self) -> Response {
+ Empty::new().into_response()
+ }
+}
+
+impl IntoResponse for Infallible {
+ fn into_response(self) -> Response {
+ match self {}
+ }
+}
+
+impl<T, E> IntoResponse for Result<T, E>
+where
+ T: IntoResponse,
+ E: IntoResponse,
+{
+ fn into_response(self) -> Response {
+ match self {
+ Ok(value) => value.into_response(),
+ Err(err) => err.into_response(),
+ }
+ }
+}
+
+impl<B> IntoResponse for Response<B>
+where
+ B: http_body::Body<Data = Bytes> + Send + 'static,
+ B::Error: Into<BoxError>,
+{
+ fn into_response(self) -> Response {
+ self.map(body::boxed)
+ }
+}
+
+impl IntoResponse for http::response::Parts {
+ fn into_response(self) -> Response {
+ Response::from_parts(self, body::boxed(Empty::new()))
+ }
+}
+
+impl IntoResponse for Full<Bytes> {
+ fn into_response(self) -> Response {
+ Response::new(body::boxed(self))
+ }
+}
+
+impl IntoResponse for Empty<Bytes> {
+ fn into_response(self) -> Response {
+ Response::new(body::boxed(self))
+ }
+}
+
+impl<E> IntoResponse for http_body::combinators::BoxBody<Bytes, E>
+where
+ E: Into<BoxError> + 'static,
+{
+ fn into_response(self) -> Response {
+ Response::new(body::boxed(self))
+ }
+}
+
+impl<E> IntoResponse for http_body::combinators::UnsyncBoxBody<Bytes, E>
+where
+ E: Into<BoxError> + 'static,
+{
+ fn into_response(self) -> Response {
+ Response::new(body::boxed(self))
+ }
+}
+
+impl<B, F> IntoResponse for MapData<B, F>
+where
+ B: http_body::Body + Send + 'static,
+ F: FnMut(B::Data) -> Bytes + Send + 'static,
+ B::Error: Into<BoxError>,
+{
+ fn into_response(self) -> Response {
+ Response::new(body::boxed(self))
+ }
+}
+
+impl<B, F, E> IntoResponse for MapErr<B, F>
+where
+ B: http_body::Body<Data = Bytes> + Send + 'static,
+ F: FnMut(B::Error) -> E + Send + 'static,
+ E: Into<BoxError>,
+{
+ fn into_response(self) -> Response {
+ Response::new(body::boxed(self))
+ }
+}
+
+impl IntoResponse for &'static str {
+ fn into_response(self) -> Response {
+ Cow::Borrowed(self).into_response()
+ }
+}
+
+impl IntoResponse for String {
+ fn into_response(self) -> Response {
+ Cow::<'static, str>::Owned(self).into_response()
+ }
+}
+
+impl IntoResponse for Cow<'static, str> {
+ fn into_response(self) -> Response {
+ let mut res = Full::from(self).into_response();
+ res.headers_mut().insert(
+ header::CONTENT_TYPE,
+ HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()),
+ );
+ res
+ }
+}
+
+impl IntoResponse for Bytes {
+ fn into_response(self) -> Response {
+ let mut res = Full::from(self).into_response();
+ res.headers_mut().insert(
+ header::CONTENT_TYPE,
+ HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()),
+ );
+ res
+ }
+}
+
+impl IntoResponse for BytesMut {
+ fn into_response(self) -> Response {
+ self.freeze().into_response()
+ }
+}
+
+impl<T, U> IntoResponse for Chain<T, U>
+where
+ T: Buf + Unpin + Send + 'static,
+ U: Buf + Unpin + Send + 'static,
+{
+ fn into_response(self) -> Response {
+ let (first, second) = self.into_inner();
+ let mut res = Response::new(body::boxed(BytesChainBody {
+ first: Some(first),
+ second: Some(second),
+ }));
+ res.headers_mut().insert(
+ header::CONTENT_TYPE,
+ HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()),
+ );
+ res
+ }
+}
+
+struct BytesChainBody<T, U> {
+ first: Option<T>,
+ second: Option<U>,
+}
+
+impl<T, U> http_body::Body for BytesChainBody<T, U>
+where
+ T: Buf + Unpin,
+ U: Buf + Unpin,
+{
+ type Data = Bytes;
+ type Error = Infallible;
+
+ fn poll_data(
+ mut self: Pin<&mut Self>,
+ _cx: &mut Context<'_>,
+ ) -> Poll<Option<Result<Self::Data, Self::Error>>> {
+ if let Some(mut buf) = self.first.take() {
+ let bytes = buf.copy_to_bytes(buf.remaining());
+ return Poll::Ready(Some(Ok(bytes)));
+ }
+
+ if let Some(mut buf) = self.second.take() {
+ let bytes = buf.copy_to_bytes(buf.remaining());
+ return Poll::Ready(Some(Ok(bytes)));
+ }
+
+ Poll::Ready(None)
+ }
+
+ fn poll_trailers(
+ self: Pin<&mut Self>,
+ _cx: &mut Context<'_>,
+ ) -> Poll<Result<Option<HeaderMap>, Self::Error>> {
+ Poll::Ready(Ok(None))
+ }
+
+ fn is_end_stream(&self) -> bool {
+ self.first.is_none() && self.second.is_none()
+ }
+
+ fn size_hint(&self) -> SizeHint {
+ match (self.first.as_ref(), self.second.as_ref()) {
+ (Some(first), Some(second)) => {
+ let total_size = first.remaining() + second.remaining();
+ SizeHint::with_exact(total_size as u64)
+ }
+ (Some(buf), None) => SizeHint::with_exact(buf.remaining() as u64),
+ (None, Some(buf)) => SizeHint::with_exact(buf.remaining() as u64),
+ (None, None) => SizeHint::with_exact(0),
+ }
+ }
+}
+
+impl IntoResponse for &'static [u8] {
+ fn into_response(self) -> Response {
+ Cow::Borrowed(self).into_response()
+ }
+}
+
+impl<const N: usize> IntoResponse for &'static [u8; N] {
+ fn into_response(self) -> Response {
+ self.as_slice().into_response()
+ }
+}
+
+impl<const N: usize> IntoResponse for [u8; N] {
+ fn into_response(self) -> Response {
+ self.to_vec().into_response()
+ }
+}
+
+impl IntoResponse for Vec<u8> {
+ fn into_response(self) -> Response {
+ Cow::<'static, [u8]>::Owned(self).into_response()
+ }
+}
+
+impl IntoResponse for Cow<'static, [u8]> {
+ fn into_response(self) -> Response {
+ let mut res = Full::from(self).into_response();
+ res.headers_mut().insert(
+ header::CONTENT_TYPE,
+ HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()),
+ );
+ res
+ }
+}
+
+impl<R> IntoResponse for (StatusCode, R)
+where
+ R: IntoResponse,
+{
+ fn into_response(self) -> Response {
+ let mut res = self.1.into_response();
+ *res.status_mut() = self.0;
+ res
+ }
+}
+
+impl IntoResponse for HeaderMap {
+ fn into_response(self) -> Response {
+ let mut res = ().into_response();
+ *res.headers_mut() = self;
+ res
+ }
+}
+
+impl IntoResponse for Extensions {
+ fn into_response(self) -> Response {
+ let mut res = ().into_response();
+ *res.extensions_mut() = self;
+ res
+ }
+}
+
+impl<K, V, const N: usize> IntoResponse for [(K, V); N]
+where
+ K: TryInto<HeaderName>,
+ K::Error: fmt::Display,
+ V: TryInto<HeaderValue>,
+ V::Error: fmt::Display,
+{
+ fn into_response(self) -> Response {
+ (self, ()).into_response()
+ }
+}
+
+impl<R> IntoResponse for (http::response::Parts, R)
+where
+ R: IntoResponse,
+{
+ fn into_response(self) -> Response {
+ let (parts, res) = self;
+ (parts.status, parts.headers, parts.extensions, res).into_response()
+ }
+}
+
+impl<R> IntoResponse for (http::response::Response<()>, R)
+where
+ R: IntoResponse,
+{
+ fn into_response(self) -> Response {
+ let (template, res) = self;
+ let (parts, ()) = template.into_parts();
+ (parts, res).into_response()
+ }
+}
+
+macro_rules! impl_into_response {
+ ( $($ty:ident),* $(,)? ) => {
+ #[allow(non_snake_case)]
+ impl<R, $($ty,)*> IntoResponse for ($($ty),*, R)
+ where
+ $( $ty: IntoResponseParts, )*
+ R: IntoResponse,
+ {
+ fn into_response(self) -> Response {
+ let ($($ty),*, res) = self;
+
+ let res = res.into_response();
+ let parts = ResponseParts { res };
+
+ $(
+ let parts = match $ty.into_response_parts(parts) {
+ Ok(parts) => parts,
+ Err(err) => {
+ return err.into_response();
+ }
+ };
+ )*
+
+ parts.res
+ }
+ }
+
+ #[allow(non_snake_case)]
+ impl<R, $($ty,)*> IntoResponse for (StatusCode, $($ty),*, R)
+ where
+ $( $ty: IntoResponseParts, )*
+ R: IntoResponse,
+ {
+ fn into_response(self) -> Response {
+ let (status, $($ty),*, res) = self;
+
+ let res = res.into_response();
+ let parts = ResponseParts { res };
+
+ $(
+ let parts = match $ty.into_response_parts(parts) {
+ Ok(parts) => parts,
+ Err(err) => {
+ return err.into_response();
+ }
+ };
+ )*
+
+ (status, parts.res).into_response()
+ }
+ }
+
+ #[allow(non_snake_case)]
+ impl<R, $($ty,)*> IntoResponse for (http::response::Parts, $($ty),*, R)
+ where
+ $( $ty: IntoResponseParts, )*
+ R: IntoResponse,
+ {
+ fn into_response(self) -> Response {
+ let (outer_parts, $($ty),*, res) = self;
+
+ let res = res.into_response();
+ let parts = ResponseParts { res };
+ $(
+ let parts = match $ty.into_response_parts(parts) {
+ Ok(parts) => parts,
+ Err(err) => {
+ return err.into_response();
+ }
+ };
+ )*
+
+ (outer_parts, parts.res).into_response()
+ }
+ }
+
+ #[allow(non_snake_case)]
+ impl<R, $($ty,)*> IntoResponse for (http::response::Response<()>, $($ty),*, R)
+ where
+ $( $ty: IntoResponseParts, )*
+ R: IntoResponse,
+ {
+ fn into_response(self) -> Response {
+ let (template, $($ty),*, res) = self;
+ let (parts, ()) = template.into_parts();
+ (parts, $($ty),*, res).into_response()
+ }
+ }
+ }
+}
+
+all_the_tuples_no_last_special_case!(impl_into_response);
diff --git a/src/response/into_response_parts.rs b/src/response/into_response_parts.rs
new file mode 100644
index 0000000..60f0b80
--- /dev/null
+++ b/src/response/into_response_parts.rs
@@ -0,0 +1,260 @@
+use super::{IntoResponse, Response};
+use http::{
+ header::{HeaderMap, HeaderName, HeaderValue},
+ Extensions, StatusCode,
+};
+use std::{convert::Infallible, fmt};
+
+/// Trait for adding headers and extensions to a response.
+///
+/// # Example
+///
+/// ```rust
+/// use axum::{
+/// response::{ResponseParts, IntoResponse, IntoResponseParts, Response},
+/// http::{StatusCode, header::{HeaderName, HeaderValue}},
+/// };
+///
+/// // Hypothetical helper type for setting a single header
+/// struct SetHeader<'a>(&'a str, &'a str);
+///
+/// impl<'a> IntoResponseParts for SetHeader<'a> {
+/// type Error = (StatusCode, String);
+///
+/// fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
+/// match (self.0.parse::<HeaderName>(), self.1.parse::<HeaderValue>()) {
+/// (Ok(name), Ok(value)) => {
+/// res.headers_mut().insert(name, value);
+/// },
+/// (Err(_), _) => {
+/// return Err((
+/// StatusCode::INTERNAL_SERVER_ERROR,
+/// format!("Invalid header name {}", self.0),
+/// ));
+/// },
+/// (_, Err(_)) => {
+/// return Err((
+/// StatusCode::INTERNAL_SERVER_ERROR,
+/// format!("Invalid header value {}", self.1),
+/// ));
+/// },
+/// }
+///
+/// Ok(res)
+/// }
+/// }
+///
+/// // Its 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 {
+/// // This gives an empty response with the header
+/// (self, ()).into_response()
+/// }
+/// }
+///
+/// // We can now return `SetHeader` in responses
+/// //
+/// // Note that returning `impl IntoResponse` might be easier if the response has many parts to
+/// // it. The return type is written out here for clarity.
+/// async fn handler() -> (SetHeader<'static>, SetHeader<'static>, &'static str) {
+/// (
+/// SetHeader("server", "axum"),
+/// SetHeader("x-foo", "custom"),
+/// "body",
+/// )
+/// }
+///
+/// // Or on its own as the whole response
+/// async fn other_handler() -> SetHeader<'static> {
+/// SetHeader("x-foo", "custom")
+/// }
+/// ```
+pub trait IntoResponseParts {
+ /// The type returned in the event of an error.
+ ///
+ /// This can be used to fallibly convert types into headers or extensions.
+ type Error: IntoResponse;
+
+ /// Set parts of the response
+ fn into_response_parts(self, res: ResponseParts) -> Result<ResponseParts, Self::Error>;
+}
+
+impl<T> IntoResponseParts for Option<T>
+where
+ T: IntoResponseParts,
+{
+ type Error = T::Error;
+
+ fn into_response_parts(self, res: ResponseParts) -> Result<ResponseParts, Self::Error> {
+ if let Some(inner) = self {
+ inner.into_response_parts(res)
+ } else {
+ Ok(res)
+ }
+ }
+}
+
+/// Parts of a response.
+///
+/// Used with [`IntoResponseParts`].
+#[derive(Debug)]
+pub struct ResponseParts {
+ pub(crate) res: Response,
+}
+
+impl ResponseParts {
+ /// Gets a reference to the response headers.
+ pub fn headers(&self) -> &HeaderMap {
+ self.res.headers()
+ }
+
+ /// Gets a mutable reference to the response headers.
+ pub fn headers_mut(&mut self) -> &mut HeaderMap {
+ self.res.headers_mut()
+ }
+
+ /// Gets a reference to the response extensions.
+ pub fn extensions(&self) -> &Extensions {
+ self.res.extensions()
+ }
+
+ /// Gets a mutable reference to the response extensions.
+ pub fn extensions_mut(&mut self) -> &mut Extensions {
+ self.res.extensions_mut()
+ }
+}
+
+impl IntoResponseParts for HeaderMap {
+ type Error = Infallible;
+
+ fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
+ res.headers_mut().extend(self);
+ Ok(res)
+ }
+}
+
+impl<K, V, const N: usize> IntoResponseParts for [(K, V); N]
+where
+ K: TryInto<HeaderName>,
+ K::Error: fmt::Display,
+ V: TryInto<HeaderValue>,
+ V::Error: fmt::Display,
+{
+ type Error = TryIntoHeaderError<K::Error, V::Error>;
+
+ fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
+ for (key, value) in self {
+ let key = key.try_into().map_err(TryIntoHeaderError::key)?;
+ let value = value.try_into().map_err(TryIntoHeaderError::value)?;
+ res.headers_mut().insert(key, value);
+ }
+
+ Ok(res)
+ }
+}
+
+/// Error returned if converting a value to a header fails.
+#[derive(Debug)]
+pub struct TryIntoHeaderError<K, V> {
+ kind: TryIntoHeaderErrorKind<K, V>,
+}
+
+impl<K, V> TryIntoHeaderError<K, V> {
+ pub(super) fn key(err: K) -> Self {
+ Self {
+ kind: TryIntoHeaderErrorKind::Key(err),
+ }
+ }
+
+ pub(super) fn value(err: V) -> Self {
+ Self {
+ kind: TryIntoHeaderErrorKind::Value(err),
+ }
+ }
+}
+
+#[derive(Debug)]
+enum TryIntoHeaderErrorKind<K, V> {
+ Key(K),
+ Value(V),
+}
+
+impl<K, V> IntoResponse for TryIntoHeaderError<K, V>
+where
+ K: fmt::Display,
+ V: fmt::Display,
+{
+ fn into_response(self) -> Response {
+ match self.kind {
+ TryIntoHeaderErrorKind::Key(inner) => {
+ (StatusCode::INTERNAL_SERVER_ERROR, inner.to_string()).into_response()
+ }
+ TryIntoHeaderErrorKind::Value(inner) => {
+ (StatusCode::INTERNAL_SERVER_ERROR, inner.to_string()).into_response()
+ }
+ }
+ }
+}
+
+impl<K, V> fmt::Display for TryIntoHeaderError<K, V> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.kind {
+ TryIntoHeaderErrorKind::Key(_) => write!(f, "failed to convert key to a header name"),
+ TryIntoHeaderErrorKind::Value(_) => {
+ write!(f, "failed to convert value to a header value")
+ }
+ }
+ }
+}
+
+impl<K, V> std::error::Error for TryIntoHeaderError<K, V>
+where
+ K: std::error::Error + 'static,
+ V: std::error::Error + 'static,
+{
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match &self.kind {
+ TryIntoHeaderErrorKind::Key(inner) => Some(inner),
+ TryIntoHeaderErrorKind::Value(inner) => Some(inner),
+ }
+ }
+}
+
+macro_rules! impl_into_response_parts {
+ ( $($ty:ident),* $(,)? ) => {
+ #[allow(non_snake_case)]
+ impl<$($ty,)*> IntoResponseParts for ($($ty,)*)
+ where
+ $( $ty: IntoResponseParts, )*
+ {
+ type Error = Response;
+
+ fn into_response_parts(self, res: ResponseParts) -> Result<ResponseParts, Self::Error> {
+ let ($($ty,)*) = self;
+
+ $(
+ let res = match $ty.into_response_parts(res) {
+ Ok(res) => res,
+ Err(err) => {
+ return Err(err.into_response());
+ }
+ };
+ )*
+
+ Ok(res)
+ }
+ }
+ }
+}
+
+all_the_tuples_no_last_special_case!(impl_into_response_parts);
+
+impl IntoResponseParts for Extensions {
+ type Error = Infallible;
+
+ fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
+ res.extensions_mut().extend(self);
+ Ok(res)
+ }
+}
diff --git a/src/response/mod.rs b/src/response/mod.rs
new file mode 100644
index 0000000..d66dfec
--- /dev/null
+++ b/src/response/mod.rs
@@ -0,0 +1,129 @@
+//! Types and traits for generating responses.
+//!
+//! See [`axum::response`] for more details.
+//!
+//! [`axum::response`]: https://docs.rs/axum/latest/axum/response/index.html
+
+use crate::body::BoxBody;
+
+mod append_headers;
+mod into_response;
+mod into_response_parts;
+
+pub use self::{
+ append_headers::AppendHeaders,
+ into_response::IntoResponse,
+ into_response_parts::{IntoResponseParts, ResponseParts, TryIntoHeaderError},
+};
+
+/// Type alias for [`http::Response`] whose body type defaults to [`BoxBody`], the most common body
+/// type used with axum.
+pub type Response<T = BoxBody> = http::Response<T>;
+
+/// An [`IntoResponse`]-based result type that uses [`ErrorResponse`] as the error type.
+///
+/// All types which implement [`IntoResponse`] can be converted to an [`ErrorResponse`]. This makes
+/// it useful as a general purpose error type for functions which combine multiple distinct error
+/// types that all implement [`IntoResponse`].
+///
+/// # Example
+///
+/// ```
+/// use axum::{
+/// response::{IntoResponse, Response},
+/// http::StatusCode,
+/// };
+///
+/// // two fallible functions with different error types
+/// fn try_something() -> Result<(), ErrorA> {
+/// // ...
+/// # unimplemented!()
+/// }
+///
+/// fn try_something_else() -> Result<(), ErrorB> {
+/// // ...
+/// # unimplemented!()
+/// }
+///
+/// // each error type implements `IntoResponse`
+/// struct ErrorA;
+///
+/// impl IntoResponse for ErrorA {
+/// fn into_response(self) -> Response {
+/// // ...
+/// # unimplemented!()
+/// }
+/// }
+///
+/// enum ErrorB {
+/// SomethingWentWrong,
+/// }
+///
+/// impl IntoResponse for ErrorB {
+/// fn into_response(self) -> Response {
+/// // ...
+/// # unimplemented!()
+/// }
+/// }
+///
+/// // we can combine them using `axum::response::Result` and still use `?`
+/// async fn handler() -> axum::response::Result<&'static str> {
+/// // the errors are automatically converted to `ErrorResponse`
+/// try_something()?;
+/// try_something_else()?;
+///
+/// Ok("it worked!")
+/// }
+/// ```
+///
+/// # As a replacement for `std::result::Result`
+///
+/// Since `axum::response::Result` has a default error type you only have to specify the `Ok` type:
+///
+/// ```
+/// use axum::{
+/// response::{IntoResponse, Response, Result},
+/// http::StatusCode,
+/// };
+///
+/// // `Result<T>` automatically uses `ErrorResponse` as the error type.
+/// async fn handler() -> Result<&'static str> {
+/// try_something()?;
+///
+/// Ok("it worked!")
+/// }
+///
+/// // You can still specify the error even if you've imported `axum::response::Result`
+/// fn try_something() -> Result<(), StatusCode> {
+/// // ...
+/// # unimplemented!()
+/// }
+/// ```
+pub type Result<T, E = ErrorResponse> = std::result::Result<T, E>;
+
+impl<T> IntoResponse for Result<T>
+where
+ T: IntoResponse,
+{
+ fn into_response(self) -> Response {
+ match self {
+ Ok(ok) => ok.into_response(),
+ Err(err) => err.0,
+ }
+ }
+}
+
+/// An [`IntoResponse`]-based error type
+///
+/// See [`Result`] for more details.
+#[derive(Debug)]
+pub struct ErrorResponse(Response);
+
+impl<T> From<T> for ErrorResponse
+where
+ T: IntoResponse,
+{
+ fn from(value: T) -> Self {
+ Self(value.into_response())
+ }
+}