Refactor default headers to be injected dynamically (#367)

This commit is contained in:
Gregory Schier
2026-01-19 07:29:00 -08:00
committed by GitHub
parent 1893b8f8dd
commit beb47a6b6a
13 changed files with 106 additions and 33 deletions

View File

@@ -0,0 +1,12 @@
-- Filter out headers that match the hardcoded defaults (User-Agent: yaak, Accept: */*),
-- keeping any other custom headers the user may have added.
UPDATE workspaces
SET headers = (
SELECT json_group_array(json(value))
FROM json_each(headers)
WHERE NOT (
(LOWER(json_extract(value, '$.name')) = 'user-agent' AND json_extract(value, '$.value') = 'yaak')
OR (LOWER(json_extract(value, '$.name')) = 'accept' AND json_extract(value, '$.value') = '*/*')
)
)
WHERE json_array_length(headers) > 0;

View File

@@ -1,3 +1,4 @@
use super::dedupe_headers;
use crate::db_context::DbContext;
use crate::error::Result;
use crate::models::{GrpcRequest, GrpcRequestIden, HttpRequestHeader};
@@ -87,6 +88,6 @@ impl<'a> DbContext<'a> {
metadata.append(&mut grpc_request.metadata.clone());
Ok(metadata)
Ok(dedupe_headers(metadata))
}
}

View File

@@ -1,3 +1,4 @@
use super::dedupe_headers;
use crate::db_context::DbContext;
use crate::error::Result;
use crate::models::{Folder, FolderIden, HttpRequest, HttpRequestHeader, HttpRequestIden};
@@ -87,7 +88,7 @@ impl<'a> DbContext<'a> {
headers.append(&mut http_request.headers.clone());
Ok(headers)
Ok(dedupe_headers(headers))
}
pub fn list_http_requests_for_folder_recursive(

View File

@@ -19,6 +19,26 @@ mod websocket_connections;
mod websocket_events;
mod websocket_requests;
mod workspace_metas;
mod workspaces;
pub mod workspaces;
const MAX_HISTORY_ITEMS: usize = 20;
use crate::models::HttpRequestHeader;
use std::collections::HashMap;
/// Deduplicate headers by name (case-insensitive), keeping the latest (most specific) value.
/// Preserves the order of first occurrence for each header name.
pub(crate) fn dedupe_headers(headers: Vec<HttpRequestHeader>) -> Vec<HttpRequestHeader> {
let mut index_by_name: HashMap<String, usize> = HashMap::new();
let mut deduped: Vec<HttpRequestHeader> = Vec::new();
for header in headers {
let key = header.name.to_lowercase();
if let Some(&idx) = index_by_name.get(&key) {
deduped[idx] = header;
} else {
index_by_name.insert(key, deduped.len());
deduped.push(header);
}
}
deduped
}

View File

@@ -1,3 +1,4 @@
use super::dedupe_headers;
use crate::db_context::DbContext;
use crate::error::Result;
use crate::models::{HttpRequestHeader, WebsocketRequest, WebsocketRequestIden};
@@ -95,6 +96,6 @@ impl<'a> DbContext<'a> {
headers.append(&mut websocket_request.headers.clone());
Ok(headers)
Ok(dedupe_headers(headers))
}
}

View File

@@ -65,28 +65,7 @@ impl<'a> DbContext<'a> {
}
pub fn upsert_workspace(&self, w: &Workspace, source: &UpdateSource) -> Result<Workspace> {
let mut workspace = w.clone();
// Add default headers only for NEW workspaces (empty ID means insert, not update)
// This prevents re-adding headers if a user intentionally removes all headers
if workspace.id.is_empty() && workspace.headers.is_empty() {
workspace.headers = vec![
HttpRequestHeader {
enabled: true,
name: "User-Agent".to_string(),
value: "yaak".to_string(),
id: None,
},
HttpRequestHeader {
enabled: true,
name: "Accept".to_string(),
value: "*/*".to_string(),
id: None,
},
];
}
self.upsert(&workspace, source)
self.upsert(w, source)
}
pub fn resolve_auth_for_workspace(
@@ -101,6 +80,28 @@ impl<'a> DbContext<'a> {
}
pub fn resolve_headers_for_workspace(&self, workspace: &Workspace) -> Vec<HttpRequestHeader> {
workspace.headers.clone()
let mut headers = default_headers();
headers.extend(workspace.headers.clone());
headers
}
}
/// Global default headers that are always sent with requests unless overridden.
/// These are prepended to the inheritance chain so workspace/folder/request headers
/// can override or disable them.
pub fn default_headers() -> Vec<HttpRequestHeader> {
vec![
HttpRequestHeader {
enabled: true,
name: "User-Agent".to_string(),
value: "yaak".to_string(),
id: None,
},
HttpRequestHeader {
enabled: true,
name: "Accept".to_string(),
value: "*/*".to_string(),
id: None,
},
]
}