Fix Accept header parsing for proper content negotiation

- Parse Accept header from nginx request headers
- Iterate through headers list to find Accept
- Compare positions of application/json vs text/html
- Return JSON if application/json appears first or alone
- Default to HTML if no Accept header or text/html preferred

Working:
- curl -H 'Accept: application/json' → Returns JSON
- curl (no header) → Returns HTML
- curl -H 'Accept: text/html' → Returns HTML

All endpoints support both formats via Accept header.
This commit is contained in:
Edward Langley
2025-11-15 17:29:12 -08:00
parent 4f0dc76367
commit 38487771fb

View File

@ -19,20 +19,43 @@ impl ContentType {
/// Determine response content type based on Accept header
pub fn negotiate_content_type(request: &Request) -> ContentType {
// For now, check query parameter as a simple way to request JSON
// Full Accept header parsing would require more nginx FFI work
let r: *const ngx::ffi::ngx_http_request_t = request.into();
unsafe {
// Check args for format=json
let args = (*r).args;
if args.len > 0 && !args.data.is_null() {
let args_slice = std::slice::from_raw_parts(args.data, args.len);
if let Ok(args_str) = std::str::from_utf8(args_slice) {
if args_str.contains("format=json") {
return ContentType::Json;
let headers_in = &(*r).headers_in;
// Iterate through all headers to find Accept
let mut current = headers_in.headers.part.elts as *mut ngx::ffi::ngx_table_elt_t;
let nelts = headers_in.headers.part.nelts;
for _ in 0..nelts {
if current.is_null() {
break;
}
let header = &*current;
if let Ok(key) = header.key.to_str() {
if key.eq_ignore_ascii_case("accept") {
if let Ok(value) = header.value.to_str() {
let value_lower = value.to_lowercase();
// Check if JSON is preferred over HTML
if value_lower.contains("application/json") {
// If it's the only type or appears before text/html, use JSON
let json_pos = value_lower.find("application/json");
let html_pos = value_lower.find("text/html");
match (json_pos, html_pos) {
(Some(_), None) => return ContentType::Json,
(Some(j), Some(h)) if j < h => return ContentType::Json,
_ => {}
}
}
}
}
}
current = current.add(1);
}
}