fix(api): image_get 500 error for non-ASCII filename uploads
- Fixes 500 error when uploading images with non-ASCII filenames via /api/image_get - Improves file path handling to support both development and Docker environments - Adds exception handling to gracefully fall back to Docker path logic if path correction fails - Ensures robust error handling so path issues do not crash the entire endpoint
keyboardstaff committed
Mar 26, 2026 at 01:19 UTC
1160195fb5994a182689ffbc5f1610f407a74dd9
1 file changed
+27
-19
api/image_get.py
+27
-19
@@ -1,5 +1,6 @@
1
import base64
2
import os
3
+from urllib.parse import quote
4
from helpers.api import ApiHandler, Request, Response, send_file
5
from helpers import files, runtime
6
import io
@@ -47,24 +48,31 @@ class ImageGet(ApiHandler):
48
49
# in development environment, try to serve the image from local file system if exists, otherwise from docker
50
if runtime.is_development():
50
- if files.exists(path):
51
- response = send_file(path)
52
- elif await runtime.call_development_function(files.exists, path):
53
- b64_content = await runtime.call_development_function(
54
- files.read_file_base64, path
55
- )
56
- file_content = base64.b64decode(b64_content)
57
- mime_type, _ = guess_type(filename)
58
- if not mime_type:
59
- mime_type = "application/octet-stream"
60
- response = send_file(
61
- io.BytesIO(file_content),
62
- mimetype=mime_type,
63
- as_attachment=False,
64
- download_name=filename,
65
- )
51
+ # Convert /a0/... Docker paths to local absolute paths
52
+ local_path = files.fix_dev_path(path)
53
+ if files.exists(local_path):
54
+ response = send_file(local_path)
55
else:
67
- response = _send_fallback_icon("image")
56
+ # Try fetching from Docker via RFC as fallback
57
+ try:
58
+ if await runtime.call_development_function(files.exists, path):
59
+ b64_content = await runtime.call_development_function(
60
+ files.read_file_base64, path
61
+ )
62
+ file_content = base64.b64decode(b64_content)
63
+ mime_type, _ = guess_type(filename)
64
+ if not mime_type:
65
+ mime_type = "application/octet-stream"
66
+ response = send_file(
67
+ io.BytesIO(file_content),
68
+ mimetype=mime_type,
69
+ as_attachment=False,
70
+ download_name=filename,
71
+ )
72
+ else:
73
+ response = _send_fallback_icon("image")
74
+ except Exception:
75
+ response = _send_fallback_icon("image")
76
else:
77
if files.exists(path):
78
response = send_file(path)
@@ -74,7 +82,7 @@ class ImageGet(ApiHandler):
82
# Add cache headers for better device sync performance
83
response.headers["Cache-Control"] = "public, max-age=3600"
84
response.headers["X-File-Type"] = "image"
77
- response.headers["X-File-Name"] = filename
85
+ response.headers["X-File-Name"] = quote(filename)
86
return response
87
else:
88
# Handle non-image files with fallback icons
@@ -135,7 +143,7 @@ def _send_file_type_icon(file_ext, filename=None):
143
response.headers["X-File-Type"] = "icon"
144
response.headers["X-Icon-Type"] = icon_name
145
if filename:
138
- response.headers["X-File-Name"] = filename
146
+ response.headers["X-File-Name"] = quote(filename)
147
148
return response
149