Skip to content

Commit

Permalink
Add AppendHeaders
Browse files Browse the repository at this point in the history
  • Loading branch information
davidpdrsn committed Apr 9, 2022
1 parent f13eab8 commit eb3d1aa
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 25 deletions.
2 changes: 1 addition & 1 deletion axum-core/CHANGELOG.md
Expand Up @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

# Unreleased

- None.
- **added:** Add `AppendHeaders` for appending headers to a response rather than overriding them

# 0.2.1 (03. April, 2022)

Expand Down
65 changes: 65 additions & 0 deletions axum-core/src/response/append_headers.rs
@@ -0,0 +1,65 @@
use super::{IntoResponse, IntoResponseParts, Response, ResponseParts, TryIntoHeaderError};
use http::header::{HeaderName, HeaderValue};
use std::{convert::TryInto, 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)]
pub struct AppendHeaders<K, V, const N: usize>(pub [(K, V); N]);

impl<K, V, const N: usize> IntoResponse for AppendHeaders<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<K, V, const N: usize> IntoResponseParts for AppendHeaders<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.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)
}
}
22 changes: 1 addition & 21 deletions axum-core/src/response/into_response.rs
Expand Up @@ -392,27 +392,7 @@ where
V::Error: fmt::Display,
{
fn into_response(self) -> Response {
let mut res = ().into_response();

for (key, value) in self {
let key = match key.try_into() {
Ok(key) => key,
Err(err) => {
return (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()).into_response()
}
};

let value = match value.try_into() {
Ok(value) => value,
Err(err) => {
return (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()).into_response()
}
};

res.headers_mut().insert(key, value);
}

res
(self, ()).into_response()
}
}

Expand Down
4 changes: 2 additions & 2 deletions axum-core/src/response/into_response_parts.rs
Expand Up @@ -161,13 +161,13 @@ pub struct TryIntoHeaderError<K, V> {
}

impl<K, V> TryIntoHeaderError<K, V> {
fn key(err: K) -> Self {
pub(super) fn key(err: K) -> Self {
Self {
kind: TryIntoHeaderErrorKind::Key(err),
}
}

fn value(err: V) -> Self {
pub(super) fn value(err: V) -> Self {
Self {
kind: TryIntoHeaderErrorKind::Value(err),
}
Expand Down
2 changes: 2 additions & 0 deletions axum-core/src/response/mod.rs
Expand Up @@ -6,10 +6,12 @@

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},
};
Expand Down
4 changes: 3 additions & 1 deletion axum/src/response/mod.rs
Expand Up @@ -19,7 +19,9 @@ pub use crate::TypedHeader;
pub use crate::Extension;

#[doc(inline)]
pub use axum_core::response::{IntoResponse, IntoResponseParts, Response, ResponseParts};
pub use axum_core::response::{
AppendHeaders, IntoResponse, IntoResponseParts, Response, ResponseParts,
};

#[doc(inline)]
pub use self::{redirect::Redirect, sse::Sse};
Expand Down

0 comments on commit eb3d1aa

Please sign in to comment.