hyperium / headers

Typed HTTP Headers from hyper
https://hyper.rs
MIT License
162 stars 84 forks source link

How do you define a custom header? #156

Closed tobymurray closed 9 months ago

tobymurray commented 9 months ago

This might just be #29 a couple years on, but imagining I have the simplest possible case: a static String for a header name and a String for the value. After looking at the example and reading the linked ticket I assumed something like this would work:

use axum::{
    headers::Header,
    http::{HeaderName, HeaderValue},
};

const CUSTOM_HEADER: &'static str = "X-Custom-Header";
const CUSTOM_HEADER_NAME: HeaderName = HeaderName::from_static(CUSTOM_HEADER);

struct CustomHeader(String);

impl Header for CustomHeader {
    fn name() -> &'static HeaderName {
        &CUSTOM_HEADER_NAME
    }

    fn decode<'i, I>(values: &mut I) -> Result<Self, axum::headers::Error>
    where
        Self: Sized,
        I: Iterator<Item = &'i axum::http::HeaderValue>,
    {
        let value = values.next().ok_or_else(axum::headers::Error::invalid)?;
        let string = value.to_str().unwrap().to_string();
        Ok(CustomHeader(string))
    }

    fn encode<E: Extend<axum::http::HeaderValue>>(&self, values: &mut E) {
        let value = HeaderValue::from_str(&self.0).unwrap();
        values.extend(std::iter::once(value));
    }
}

This yields:

error[E0515]: cannot return reference to temporary value
  --> src/custom_header.rs:12:3
   |
12 |         &CUSTOM_HEADER_NAME
   |         ^------------------
   |         ||
   |         |temporary value created here
   |         returns a reference to data owned by the current function
tobymurray commented 9 months ago

Documenting for posterity, this is not really an issue with this library, this is me not understanding a static reference to a const returns a reference to a temporary variable generally. static should be used in this context instead of const, e.g.:

use axum::{
    headers::Header,
    http::{HeaderName, HeaderValue},
};

static CUSTOM_HEADER: &'static str = "x-custom-header";
static CUSTOM_HEADER_NAME: HeaderName = HeaderName::from_static(CUSTOM_HEADER);

struct CustomHeader(String);

impl Header for CustomHeader {
    fn name() -> &'static HeaderName {
        &CUSTOM_HEADER_NAME
    }

    fn decode<'i, I>(values: &mut I) -> Result<Self, axum::headers::Error>
    where
        Self: Sized,
        I: Iterator<Item = &'i axum::http::HeaderValue>,
    {
        let value = values.next().ok_or_else(axum::headers::Error::invalid)?;
        let string = value.to_str().unwrap().to_string();
        Ok(CustomHeader(string))
    }

    fn encode<E: Extend<axum::http::HeaderValue>>(&self, values: &mut E) {
        let value = HeaderValue::from_str(&self.0).unwrap();
        values.extend(std::iter::once(value));
    }
}

Also updated to address that the header name must be lowercase or it panics.