pdk-cors-lib 1.6.0

PDK Cors Library
Documentation
// Copyright (c) 2025, Salesforce, Inc.,
// All rights reserved.
// For full license text, see the LICENSE.txt file

const PROXY_HEADER: &str = "proxy-";
const SEC_HEADER: &str = "sec-";

const HEADERS: [&str; 34] = [
    "connection",
    "user-agent",
    "accept",
    "accept-language",
    "content-language",
    "content-type",
    "accept-charset",
    "accept-encoding",
    "access-control-request-headers",
    "access-control-request-method",
    "connection",
    "content-length",
    "cookie",
    "cookie2",
    "date",
    "dnt",
    "expect",
    "host",
    "keep-alive",
    "origin",
    "referer",
    "te",
    "trailer",
    "transfer-encoding",
    "upgrade",
    "via",
    // Envoy headers
    ":authority",
    ":method",
    ":path",
    ":scheme",
    "x-forwarded-proto",
    "x-request-id",
    "x-forwarded-for",
    "x-envoy-internal",
];

#[derive(Default)]
pub(crate) struct SimpleHeaders {}

impl SimpleHeaders {
    pub(crate) fn matches(&self, header: &str) -> bool {
        let header_lowercase = header.to_lowercase();

        HEADERS.contains(&header_lowercase.as_str())
            || header_lowercase.starts_with(PROXY_HEADER)
            || header_lowercase.starts_with(SEC_HEADER)
    }
}

#[cfg(test)]
mod simple_headers_tests {
    use crate::model::request::simple_request_headers::SimpleHeaders;

    #[test]
    fn header_lowercase_matches() {
        let simple_headers = SimpleHeaders::default();

        assert!(simple_headers.matches("origin"));
        assert!(simple_headers.matches("keep-alive"));
        assert!(simple_headers.matches("accept-language"));
        assert!(simple_headers.matches("content-type"));
        assert!(simple_headers.matches("proxy-whatever"));
        assert!(simple_headers.matches("sec-whatever"));
        assert!(simple_headers.matches("x-forwarded-for"));
        assert!(simple_headers.matches("x-envoy-internal"));
    }

    #[test]
    fn header_uppercase_matches() {
        let simple_headers = SimpleHeaders::default();

        assert!(simple_headers.matches("ORIGIN"));
        assert!(simple_headers.matches("KEEP-ALIVE"));
        assert!(simple_headers.matches("ACCEPT-LANGUAGE"));
        assert!(simple_headers.matches("CONTENT-TYPE"));
        assert!(simple_headers.matches("PROXY-WHATEVER"));
        assert!(simple_headers.matches("SEC-WHATEVER"));
        assert!(simple_headers.matches("X-FORWARDED-FOR"));
        assert!(simple_headers.matches("X-ENVOY-INTERNAL"));
    }

    #[test]
    fn header_mixed_case_matches() {
        let simple_headers = SimpleHeaders::default();

        assert!(simple_headers.matches("ORiGiN"));
        assert!(simple_headers.matches("KeeP-ALIVE"));
        assert!(simple_headers.matches("ACCEPT-langUAGE"));
        assert!(simple_headers.matches("Content-Type"));
        assert!(simple_headers.matches("Proxy-WHATEVER"));
        assert!(simple_headers.matches("SEc-WhateVER"));
    }

    #[test]
    fn not_accepted_header_does_not_match() {
        let simple_headers = SimpleHeaders::default();

        assert!(!simple_headers.matches("options"));
        assert!(!simple_headers.matches("notorigin"));
    }

    #[test]
    fn envoy_special_headers_match() {
        let simple_headers = SimpleHeaders::default();

        assert!(simple_headers.matches(":authority"));
        assert!(simple_headers.matches(":method"));
        assert!(simple_headers.matches(":path"));
        assert!(simple_headers.matches(":scheme"));
        assert!(simple_headers.matches("x-forwarded-proto"));
        assert!(simple_headers.matches("x-request-id"));
        assert!(simple_headers.matches("x-forwarded-for"));
        assert!(simple_headers.matches("x-envoy-internal"));
    }
}