This document provides a comprehensive guide to handling file uploads in the sillo framework, covering both single and multiple file upload scenarios with proper validation and security considerations.
File Uploads
Section titled “File Uploads”Single File Upload
Section titled “Single File Upload”To handle a single file upload in sillo:
from sillo.http import Request, Response
@app.post("/upload")async def upload_file(request: Request, response: Response): files = await request.files if not files: return response.status(400).json({"error": "No files uploaded"})
file = files["file"] # 'file' is the field name in the form file_content = await file.read()
# Save file or process it # ...
return response.json({"filename": file.filename, "size": len(file_content)})Multiple File Uploads
Section titled “Multiple File Uploads”For handling multiple files from the same field:
@app.post("/uploads")async def upload_files(request: Request, response: Response): files = await request.files if not files: return response.status(400).json({"error": "No files uploaded"})
results = [] for file in files.getlist("files"): # 'files' is the field name file_content = await file.read() # Process each file results.append({ "filename": file.filename, "size": len(file_content) })
return response.json({"files": results})Security Considerations
Section titled “Security Considerations”File Type Validation
Section titled “File Type Validation”Validate file extensions and MIME types:
ALLOWED_EXTENSIONS = {"jpg", "jpeg", "png", "gif"}ALLOWED_MIME_TYPES = {"image/jpeg", "image/png", "image/gif"}
@app.post("/upload-image")async def upload_image(request: Request, response: Response): files = await request.files if not files: return response.status(400).json({"error": "No file uploaded"})
file = files["image"]
# Validate extension file_ext = file.filename.split(".")[-1].lower() if file_ext not in ALLOWED_EXTENSIONS: return response.status(400).json({"error": "Invalid file type"})
# Validate MIME type if file.content_type not in ALLOWED_MIME_TYPES: return response.status(400).json({"error": "Invalid MIME type"})
# Process valid file # ...Form Data with Files
Section titled “Form Data with Files”Handle mixed form data and file uploads:
@app.post("/profile")async def update_profile(request: Request, response: Response): form_data = await request.form files = await request.files
name = form_data.get("name") avatar = files.get("avatar")
if avatar: avatar_content = await avatar.read() # Save avatar # ...
return response.json({"name": name, "avatar_uploaded": bool(avatar)})Advanced Configuration
Section titled “Advanced Configuration”Custom Upload Handlers
Section titled “Custom Upload Handlers”Create middleware for file upload processing:
async def file_upload_middleware(request: Request, response: Response, call_next): if request.method == "POST" and "multipart/form-data" in request.headers.get("Content-Type", ""): # Pre-process uploads request.state.upload_dir = "/path/to/uploads"
return await call_next(request, response)
app.use(file_upload_middleware)Streaming Large Files
Section titled “Streaming Large Files”For handling very large files without memory issues:
@app.post("/upload-large")async def upload_large_file(request: Request, response: Response): files = await request.files file = files.get("file")
if not file: return response.status(400).json({"error": "No file uploaded"})
# Process in chunks chunk_size = 1024 * 1024 # 1MB chunks total_size = 0
async with open(f"/uploads/{file.filename}", "wb") as f: while True: chunk = await file.read(chunk_size) if not chunk: break await f.write(chunk) total_size += len(chunk)
return response.json({ "filename": file.filename, "size": total_size, "status": "uploaded" })Troubleshooting
Section titled “Troubleshooting”Common issues and solutions:
-
File size too large:
- Increase
max_file_sizein config - Use streaming for very large files
- Increase
-
Memory errors:
- Process files in chunks
- Use
request.stream()for direct access to the upload stream
-
File validation failures:
- Always check both filename extension and MIME type
- Consider scanning uploaded files for malware
Best Practices
Section titled “Best Practices”- Always validate file types and sizes
- Never trust original filenames - sanitize or generate new ones
- Store files outside web root when possible
- Set appropriate permissions on upload directories
- Consider virus scanning for user uploads
- Use CSRF protection for upload forms
This documentation covers the essential aspects of file upload handling in the sillo framework. For more advanced scenarios, refer to the framework’s multipart parsing and streaming capabilities.