fix: Add HEAD method support to assets proxy endpoint

- Add HEAD method handler for browser preflight requests
- Use stat_object for HEAD requests (more efficient)
- Return proper headers for HEAD requests
- This fixes 405 errors when browser checks image availability
This commit is contained in:
Apple
2025-12-02 08:47:02 -08:00
parent 55634eac9b
commit 192631c2eb

View File

@@ -325,7 +325,8 @@ async def update_agent_visibility_endpoint(
# ============================================================================= # =============================================================================
@router.get("/assets/proxy/{path:path}") @router.get("/assets/proxy/{path:path}")
async def proxy_asset(path: str): @router.head("/assets/proxy/{path:path}")
async def proxy_asset(path: str, request: Request):
""" """
Proxy endpoint for serving MinIO assets. Proxy endpoint for serving MinIO assets.
@@ -352,15 +353,12 @@ async def proxy_asset(path: str):
try: try:
client = get_minio_client() client = get_minio_client()
# Get object from MinIO # Check if object exists and get metadata
# path already contains the full object key (e.g., "microdao/logo/2025/12/02/abc123.png") try:
# ASSETS_BUCKET is prepended by get_object() stat = client.stat_object(ASSETS_BUCKET, path)
response = client.get_object(ASSETS_BUCKET, path) except Exception as e:
logger.warning(f"Asset not found in MinIO: {path}, error: {e}")
# Read data raise HTTPException(status_code=404, detail="Asset not found")
data = response.read()
response.close()
response.release_conn()
# Determine content type # Determine content type
content_type = "application/octet-stream" content_type = "application/octet-stream"
@@ -373,14 +371,36 @@ async def proxy_asset(path: str):
elif path.endswith('.gif'): elif path.endswith('.gif'):
content_type = 'image/gif' content_type = 'image/gif'
# For HEAD requests, return headers only
if request.method == 'HEAD':
from fastapi.responses import Response
return Response(
status_code=200,
headers={
'Content-Type': content_type,
'Content-Length': str(stat.size),
'Cache-Control': 'public, max-age=86400, immutable',
'Access-Control-Allow-Origin': '*',
}
)
# For GET requests, return file data
response = client.get_object(ASSETS_BUCKET, path)
data = response.read()
response.close()
response.release_conn()
return StreamingResponse( return StreamingResponse(
io.BytesIO(data), io.BytesIO(data),
media_type=content_type, media_type=content_type,
headers={ headers={
'Content-Length': str(stat.size),
'Cache-Control': 'public, max-age=86400, immutable', 'Cache-Control': 'public, max-age=86400, immutable',
'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Origin': '*',
} }
) )
except HTTPException:
raise
except Exception as e: except Exception as e:
logger.error(f"Failed to proxy asset {path}: {e}") logger.error(f"Failed to proxy asset {path}: {e}")
raise HTTPException(status_code=404, detail="Asset not found") raise HTTPException(status_code=404, detail="Asset not found")