pub mod any_request; mod batch; mod cookie_jars; mod duplicate_name; mod environments; mod folders; mod graphql_introspections; mod grpc_connections; mod grpc_events; mod grpc_requests; mod http_requests; mod http_response_events; mod http_responses; mod key_values; mod model_changes; mod plugin_key_values; mod plugins; mod settings; mod sync_states; mod websocket_connections; mod websocket_events; mod websocket_requests; mod workspace_metas; pub mod workspaces; pub use model_changes::PersistedModelChange; pub(crate) use duplicate_name::conflict_free_name; const MAX_HISTORY_ITEMS: usize = 20; use crate::models::HttpRequestHeader; use std::collections::HashSet; /// Merge a more-specific header layer over its parent. Names in the child replace /// inherited values case-insensitively, while duplicates declared together in /// either layer remain independent entries. pub(crate) fn merge_headers( mut parent: Vec, child: Vec, ) -> Vec { let child_names = child.iter().map(|header| header.name.to_lowercase()).collect::>(); parent.retain(|header| !child_names.contains(&header.name.to_lowercase())); parent.extend(child); parent } #[cfg(test)] mod tests { use super::merge_headers; use crate::models::HttpRequestHeader; fn header(name: &str, value: &str) -> HttpRequestHeader { HttpRequestHeader { name: name.to_string(), value: value.to_string(), ..Default::default() } } #[test] fn preserves_duplicate_headers_declared_in_one_layer() { let merged = merge_headers( vec![header("Cookie", "inherited=1")], vec![ header("Cookie", "required=1"), header("cookie", "optional=1"), ], ); assert_eq!( merged.iter().map(|header| header.value.as_str()).collect::>(), vec!["required=1", "optional=1"], ); } #[test] fn child_names_override_parent_names_without_affecting_other_headers() { let merged = merge_headers( vec![header("Accept", "*/*"), header("X-Parent", "kept")], vec![header("accept", "application/json")], ); assert_eq!( merged .iter() .map(|header| (header.name.as_str(), header.value.as_str())) .collect::>(), vec![("X-Parent", "kept"), ("accept", "application/json")], ); } }