feat: implement allow_binary content filtering for item endpoints
Co-authored-by: aider (openai/andrew/openrouter/qwen/qwen3-coder) <aider@aider.chat>
This commit is contained in:
@@ -9,7 +9,8 @@ use std::collections::HashMap;
|
||||
|
||||
use crate::services::async_item_service::AsyncItemService;
|
||||
use crate::services::error::CoreError;
|
||||
use crate::modes::server::common::{AppState, ApiResponse, ItemInfo, TagsQuery, ListItemsQuery, ItemInfoListResponse, ItemInfoResponse, MetadataResponse};
|
||||
use crate::modes::server::common::{AppState, ApiResponse, ItemInfo, TagsQuery, ListItemsQuery, ItemInfoListResponse, ItemInfoResponse, MetadataResponse, ItemQuery};
|
||||
use crate::common::is_binary::is_binary;
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
@@ -137,15 +138,17 @@ pub async fn handle_post_item(
|
||||
path = "/api/item/latest/content",
|
||||
operation_id = "get_item_latest_content",
|
||||
summary = "Download latest item content",
|
||||
description = "Download the raw content of the most recently stored item. The content is automatically decompressed and returned with the appropriate MIME type header for proper browser handling. If tags are specified, returns the latest item matching ALL the given tags.",
|
||||
description = "Download the raw content of the most recently stored item. The content is automatically decompressed and returned with the appropriate MIME type header for proper browser handling. If tags are specified, returns the latest item matching ALL the given tags. If allow_binary is false and the content is detected as binary, a 400 error is returned.",
|
||||
responses(
|
||||
(status = 200, description = "Successfully retrieved latest item raw content with appropriate Content-Type header set based on detected MIME type"),
|
||||
(status = 400, description = "Bad request - Content is binary but allow_binary is false"),
|
||||
(status = 401, description = "Unauthorized - Invalid or missing authentication credentials"),
|
||||
(status = 404, description = "Item not found - No items exist in the database or no items match the specified tag criteria"),
|
||||
(status = 500, description = "Internal server error - Failed to retrieve item content due to decompression or filesystem error")
|
||||
),
|
||||
params(
|
||||
("tags" = Option<String>, Query, description = "Comma-separated list of tags to filter by (e.g., 'important,work'). If specified, returns the latest item that has ALL the specified tags.")
|
||||
("tags" = Option<String>, Query, description = "Comma-separated list of tags to filter by (e.g., 'important,work'). If specified, returns the latest item that has ALL the specified tags."),
|
||||
("allow_binary" = Option<bool>, Query, description = "Whether to allow binary content to be returned (default: true). When false, returns 400 for binary files.")
|
||||
),
|
||||
security(
|
||||
("bearerAuth" = [])
|
||||
@@ -176,6 +179,20 @@ pub async fn handle_get_item_latest_content(
|
||||
let content = item_with_content.content;
|
||||
let metadata = item_with_content.item_with_meta.meta_as_map();
|
||||
|
||||
// Check if content is binary when allow_binary is false
|
||||
if !params.allow_binary {
|
||||
let is_content_binary = if let Some(binary_meta) = metadata.get("binary") {
|
||||
binary_meta == "true"
|
||||
} else {
|
||||
// If binary metadata not available, check the content
|
||||
is_binary(&content)
|
||||
};
|
||||
|
||||
if is_content_binary {
|
||||
return Err(StatusCode::BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
let mime_type = metadata
|
||||
.get("mime_type")
|
||||
.map(|s| s.to_string())
|
||||
@@ -206,16 +223,17 @@ pub async fn handle_get_item_latest_content(
|
||||
path = "/api/item/{item_id}/content",
|
||||
operation_id = "get_item_content",
|
||||
summary = "Download item content",
|
||||
description = "Download the raw content of a specific item by its ID. The content is automatically decompressed and returned with the appropriate MIME type header for proper browser handling. This endpoint is ideal for downloading files or viewing content directly in the browser.",
|
||||
description = "Download the raw content of a specific item by its ID. The content is automatically decompressed and returned with the appropriate MIME type header for proper browser handling. This endpoint is ideal for downloading files or viewing content directly in the browser. If allow_binary is false and the content is detected as binary, a 400 error is returned.",
|
||||
responses(
|
||||
(status = 200, description = "Successfully retrieved item raw content with appropriate Content-Type header set based on detected MIME type"),
|
||||
(status = 400, description = "Bad request - Invalid item ID (must be a positive integer)"),
|
||||
(status = 400, description = "Bad request - Invalid item ID (must be a positive integer) or content is binary but allow_binary is false"),
|
||||
(status = 401, description = "Unauthorized - Invalid or missing authentication credentials"),
|
||||
(status = 404, description = "Item not found - No item exists with the specified ID"),
|
||||
(status = 500, description = "Internal server error - Failed to retrieve item content due to decompression or filesystem error")
|
||||
),
|
||||
params(
|
||||
("item_id" = i64, Path, description = "Unique identifier of the item to retrieve content for (must be a positive integer)")
|
||||
("item_id" = i64, Path, description = "Unique identifier of the item to retrieve content for (must be a positive integer)"),
|
||||
("allow_binary" = Option<bool>, Query, description = "Whether to allow binary content to be returned (default: true). When false, returns 400 for binary files.")
|
||||
),
|
||||
security(
|
||||
("bearerAuth" = [])
|
||||
@@ -225,6 +243,7 @@ pub async fn handle_get_item_latest_content(
|
||||
pub async fn handle_get_item_content(
|
||||
State(state): State<AppState>,
|
||||
Path(item_id): Path<i64>,
|
||||
Query(params): Query<ItemQuery>,
|
||||
) -> Result<Response, StatusCode> {
|
||||
// Validate that item ID is positive to prevent path traversal issues
|
||||
if item_id <= 0 {
|
||||
@@ -238,6 +257,20 @@ pub async fn handle_get_item_content(
|
||||
let content = item_with_content.content;
|
||||
let metadata = item_with_content.item_with_meta.meta_as_map();
|
||||
|
||||
// Check if content is binary when allow_binary is false
|
||||
if !params.allow_binary {
|
||||
let is_content_binary = if let Some(binary_meta) = metadata.get("binary") {
|
||||
binary_meta == "true"
|
||||
} else {
|
||||
// If binary metadata not available, check the content
|
||||
is_binary(&content)
|
||||
};
|
||||
|
||||
if is_content_binary {
|
||||
return Err(StatusCode::BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
let mime_type = metadata
|
||||
.get("mime_type")
|
||||
.map(|s| s.to_string())
|
||||
|
||||
Reference in New Issue
Block a user