| """ |
| File serving utilities for FastAPI app. |
| """ |
| from fastapi.responses import FileResponse, HTMLResponse, StreamingResponse |
|
|
| HTML_EXTS = [".html", ".htm"] |
| HTML_GZ_EXT = ".html.gz" |
| IMAGE_EXTS = [".png", ".jpg", ".jpeg", ".gif", ".bmp", ".webp", ".svg"] |
| PDF_EXT = ".pdf" |
|
|
| def serve_html_file(file_resp, file_path): |
| content = file_resp.read() if hasattr(file_resp, "read") else file_resp |
| if isinstance(content, bytes): |
| content = content.decode("utf-8", errors="replace") |
| return HTMLResponse(content, media_type="text/html; charset=utf-8") |
|
|
| def serve_html_gz_file(file_resp, file_path): |
| import io |
| import unicodedata |
| content = file_resp.read() if hasattr(file_resp, "read") else file_resp |
| if not isinstance(content, bytes): |
| content = bytes(content) |
| safe_filename = file_path[:-3] |
| try: |
| safe_filename.encode('ascii') |
| except UnicodeEncodeError: |
| safe_filename = unicodedata.normalize('NFKD', safe_filename).encode('ascii', 'ignore').decode('ascii') |
| if not safe_filename: |
| safe_filename = 'file.html' |
| headers = { |
| "Content-Encoding": "gzip", |
| "Content-Disposition": f"inline; filename={safe_filename}" |
| } |
| return StreamingResponse(io.BytesIO(content), media_type="text/html", headers=headers) |
|
|
| def serve_image_file(file_resp, file_path): |
| import tempfile, os |
| from starlette.background import BackgroundTask |
| def get_image_bytes(file_resp): |
| if hasattr(file_resp, "read"): |
| return file_resp.read() |
| return file_resp if isinstance(file_resp, bytes) else bytes(file_resp) |
| image_bytes = get_image_bytes(file_resp) |
| ext = file_path.split(".")[-1].lower() |
| media_type = f"image/{'jpeg' if ext == 'jpg' else ext}" |
| with tempfile.NamedTemporaryFile(delete=False, suffix=f'.{ext}') as tmp: |
| tmp.write(image_bytes) |
| tmp_path = tmp.name |
| def cleanup(): |
| try: |
| os.remove(tmp_path) |
| except Exception: |
| pass |
| return FileResponse(tmp_path, media_type=media_type, filename=file_path, background=BackgroundTask(cleanup)) |
|
|
| def serve_binary_file(file_resp, file_path, media_type=None): |
| return FileResponse(file_resp, filename=file_path, media_type=media_type) |
|
|