use crate::constants::ASSET_ENCODING_NO_COMPRESSION;
use crate::http::types::HeaderField;
use crate::types::config::{StorageConfig, StorageConfigIFrame};
use crate::types::store::{Asset, AssetEncoding, EncodingType};
use crate::url::matching_urls;
use hex::encode;
use std::collections::HashMap;
pub fn build_headers(
asset: &Asset,
encoding: &AssetEncoding,
encoding_type: &EncodingType,
config: &StorageConfig,
) -> Vec<HeaderField> {
let mut headers: HashMap<String, String> = build_config_headers(&asset.key.full_path, config)
.into_iter()
.map(|HeaderField(key, value)| (key.to_lowercase(), value))
.collect();
for HeaderField(key, value) in &asset.headers {
headers.insert(key.to_lowercase(), value.clone());
}
if asset.key.token.is_some() {
for HeaderField(key, value) in token_headers() {
headers.insert(key.to_lowercase(), value);
}
}
headers.insert("accept-ranges".to_string(), "bytes".to_string());
headers.insert(
"etag".to_string(),
format!("\"{}\"", encode(encoding.sha256)),
);
for HeaderField(key, value) in security_headers() {
headers.insert(key.to_lowercase(), value);
}
if let Some(HeaderField(key, value)) = iframe_headers(&config.unwrap_iframe()) {
headers.insert(key.to_lowercase(), value);
}
if encoding_type.clone() != *ASSET_ENCODING_NO_COMPRESSION {
headers.insert("content-encoding".to_string(), encoding_type.to_string());
}
headers
.into_iter()
.map(|(key, value)| HeaderField(key, value))
.collect()
}
pub fn build_redirect_headers(location: &str, iframe: &StorageConfigIFrame) -> Vec<HeaderField> {
let mut headers = Vec::new();
headers.extend(security_headers());
if let Some(iframe_header) = iframe_headers(iframe) {
headers.push(iframe_header);
}
headers.push(HeaderField("Location".to_string(), location.to_string()));
headers
}
fn security_headers() -> Vec<HeaderField> {
vec![
HeaderField("X-Content-Type-Options".to_string(), "nosniff".to_string()),
HeaderField(
"Strict-Transport-Security".to_string(),
"max-age=31536000 ; includeSubDomains".to_string(),
),
HeaderField("Referrer-Policy".to_string(), "same-origin".to_string()),
]
}
fn iframe_headers(iframe: &StorageConfigIFrame) -> Option<HeaderField> {
match iframe {
StorageConfigIFrame::Deny => Some(HeaderField(
"X-Frame-Options".to_string(),
"DENY".to_string(),
)),
StorageConfigIFrame::SameOrigin => Some(HeaderField(
"X-Frame-Options".to_string(),
"SAMEORIGIN".to_string(),
)),
StorageConfigIFrame::AllowAny => None,
}
}
fn token_headers() -> Vec<HeaderField> {
vec![
HeaderField("X-Robots-Tag".to_string(), "noindex, nofollow".to_string()),
HeaderField("Cache-Control".to_string(), "private, no-store".to_string()),
]
}
pub fn build_config_headers(
requested_path: &str,
StorageConfig {
headers: config_headers,
..
}: &StorageConfig,
) -> Vec<HeaderField> {
matching_urls(requested_path, config_headers)
.iter()
.flat_map(|(_, headers)| headers.clone())
.collect()
}