Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  name.rs   Sprache: unbekannt

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::borrow::Cow;

/// Represents a header name that we know to be both valid and lowercase.
/// Internally, this avoids allocating for headers that are constant strings,
/// like the predefined ones in this crate, however even without that
/// optimization, we would still likely have an equivalent of this for use
/// as a case-insensitive string guaranteed to only have valid characters.
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash, Eq, Ord)]
pub struct HeaderName(pub(super) Cow<'static, str>);

/// Indicates an invalid header name. Note that we only emit
/// this for response headers, for request headers, we panic
/// instead. This is because it would likely come through as
/// a network error if we emitted it for local headers, when
/// it's actually a bug that we'd need to fix.
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
#[error("Invalid header name: {0:?}")]
pub struct InvalidHeaderName(Cow<'static, str>);

impl From<&'static str> for HeaderName {
    fn from(s: &'static str) -> HeaderName {
        match HeaderName::new(s) {
            Ok(v) => v,
            Err(e) => {
                panic!("Illegal locally specified header {}", e);
            }
        }
    }
}

impl From<String> for HeaderName {
    fn from(s: String) -> HeaderName {
        match HeaderName::new(s) {
            Ok(v) => v,
            Err(e) => {
                panic!("Illegal locally specified header {}", e);
            }
        }
    }
}

impl From<Cow<'static, str>> for HeaderName {
    fn from(s: Cow<'static, str>) -> HeaderName {
        match HeaderName::new(s) {
            Ok(v) => v,
            Err(e) => {
                panic!("Illegal locally specified header {}", e);
            }
        }
    }
}

impl InvalidHeaderName {
    pub fn name(&self) -> &str {
        &self.0[..]
    }
}

fn validate_header(mut name: Cow<'static, str>) -> Result<HeaderName, InvalidHeaderName> {
    if name.len() == 0 {
        return Err(invalid_header_name(name));
    }
    let mut need_lower_case = false;
    for b in name.bytes() {
        let validity = VALID_HEADER_LUT[b as usize];
        if validity == 0 {
            return Err(invalid_header_name(name));
        }
        if validity == 2 {
            need_lower_case = true;
        }
    }
    if need_lower_case {
        // Only do this if needed, since it causes us to own the header.
        name.to_mut().make_ascii_lowercase();
    }
    Ok(HeaderName(name))
}

impl HeaderName {
    /// Create a new header. In general you likely want to use `HeaderName::from(s)`
    /// instead for headers being specified locally (This will panic instead of
    /// returning a Result, since we have control over headers we specify locally,
    /// and want to know if we specify an illegal one).
    #[inline]
    pub fn new<S: Into<Cow<'static, str>>>(s: S) -> Result<Self, InvalidHeaderName> {
        validate_header(s.into())
    }

    #[inline]
    pub fn as_str(&self) -> &str {
        &self.0[..]
    }
}

impl std::fmt::Display for HeaderName {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(self.as_str())
    }
}

// Separate for dumb micro-optimization reasons.
#[cold]
#[inline(never)]
fn invalid_header_name(s: Cow<'static, str>) -> InvalidHeaderName {
    log::warn!("Invalid header name: {}", s);
    InvalidHeaderName(s)
}
// Note: 0 = invalid, 1 = valid, 2 = valid but needs lowercasing. I'd use an
// enum for this, but it would make this LUT *way* harder to look at. This
// includes 0-9, a-z, A-Z (as 2), and ('!' | '#' | '$' | '%' | '&' | '\'' | '*'
// | '+' | '-' | '.' | '^' | '_' | '`' | '|' | '~'), matching the field-name
// token production defined at https://tools.ietf.org/html/rfc7230#section-3.2.
static VALID_HEADER_LUT: [u8; 256] = [
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
    0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];

impl std::ops::Deref for HeaderName {
    type Target = str;
    #[inline]
    fn deref(&self) -> &str {
        self.as_str()
    }
}

impl AsRef<str> for HeaderName {
    #[inline]
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl AsRef<[u8]> for HeaderName {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        self.as_str().as_bytes()
    }
}

impl From<HeaderName> for String {
    #[inline]
    fn from(h: HeaderName) -> Self {
        h.0.into()
    }
}

impl From<HeaderName> for Cow<'static, str> {
    #[inline]
    fn from(h: HeaderName) -> Self {
        h.0
    }
}

impl From<HeaderName> for Vec<u8> {
    #[inline]
    fn from(h: HeaderName) -> Self {
        String::from(h.0).into()
    }
}

macro_rules! partialeq_boilerplate {
    ($T0:ty, $T1:ty) => {
        // This macro is used for items with and without lifetimes.
        #[allow(clippy::extra_unused_lifetimes)]
        impl<'a> PartialEq<$T0> for $T1 {
            fn eq(&self, other: &$T0) -> bool {
                // The &* should invoke Deref::deref if it exists, no-op otherwise.
                (&*self).eq_ignore_ascii_case(&*other)
            }
        }
        #[allow(clippy::extra_unused_lifetimes)]
        impl<'a> PartialEq<$T1> for $T0 {
            fn eq(&self, other: &$T1) -> bool {
                PartialEq::eq(other, self)
            }
        }
    };
}

partialeq_boilerplate!(HeaderName, str);
partialeq_boilerplate!(HeaderName, &'a str);
partialeq_boilerplate!(HeaderName, String);
partialeq_boilerplate!(HeaderName, &'a String);
partialeq_boilerplate!(HeaderName, Cow<'a, str>);

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_lut() {
        let mut expect = [0u8; 256];
        for b in b'0'..=b'9' {
            expect[b as usize] = 1;
        }
        for b in b'a'..=b'z' {
            expect[b as usize] = 1;
        }
        for b in b'A'..=b'Z' {
            expect[b as usize] = 2;
        }
        for b in b"!#$%&'*+-.^_`|~" {
            expect[*b as usize] = 1;
        }
        assert_eq!(&VALID_HEADER_LUT[..], &expect[..]);
    }
    #[test]
    fn test_validate() {
        assert!(validate_header("".into()).is_err());
        assert!(validate_header(" foo ".into()).is_err());
        assert!(validate_header("a=b".into()).is_err());
        assert_eq!(
            validate_header("content-type".into()),
            Ok(HeaderName("content-type".into()))
        );
        assert_eq!(
            validate_header("Content-Type".into()),
            Ok(HeaderName("content-type".into()))
        );
    }
}

[ Dauer der Verarbeitung: 0.24 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge