fix: harden storage proxy and error handling
Build and Push Docker Container / build-and-push (push) Successful in 2m3s
Build and Push Docker Container / build-and-push (push) Successful in 2m3s
- Preserve Convex storage response headers while validating allowed component query parameters. - Add fallback favicon routes for common browser and resource paths. - Make Convex error tracking non-blocking so error pages still render when tracking fails. - Return clearer 405 responses and map Convex outages to 503 or 504 with Retry-After headers. - Route logging through wide-event-aware helpers to avoid duplicate logs when structured events are enabled.
This commit is contained in:
@@ -1,12 +1,17 @@
|
||||
from my_modules.app.setup import LIMITER
|
||||
from my_modules.functions import is_valid_uuid
|
||||
|
||||
from quart import Blueprint, send_from_directory, current_app, Response, redirect, abort
|
||||
from urllib.parse import urlencode
|
||||
|
||||
from quart import Blueprint, send_from_directory, current_app, Response, redirect, abort, request
|
||||
|
||||
basic_bp = Blueprint('basic', __name__)
|
||||
|
||||
@basic_bp.route('/favicon', methods=['GET'])
|
||||
@basic_bp.route('/favicon.ico', methods=['GET'])
|
||||
@basic_bp.route('/favicon-32x32.png', methods=['GET'])
|
||||
@basic_bp.route('/favicon.png', methods=['GET'])
|
||||
@basic_bp.route('/res/favicon.ico', methods=['GET'])
|
||||
@basic_bp.route('/favicon', methods=['GET'])
|
||||
@LIMITER.exempt
|
||||
async def favicon():
|
||||
file_data = await current_app.convex.get_current_favicon()
|
||||
@@ -19,11 +24,23 @@ async def robots():
|
||||
|
||||
@basic_bp.route("/storage/<path:file_id>")
|
||||
async def convex_storage_proxy(file_id:str):
|
||||
clean_file_id = file_id.split("?", 1)[0]
|
||||
if not is_valid_uuid(clean_file_id):
|
||||
if not is_valid_uuid(file_id):
|
||||
return abort(404, "Not a valid uuid")
|
||||
|
||||
return Response(
|
||||
current_app.convex.stream_from_storage(file_id, add_api_path=True),
|
||||
mimetype="application/octet-stream"
|
||||
)
|
||||
query_keys = set(request.args.keys())
|
||||
if query_keys - {"component"}:
|
||||
return abort(400, "Only the component query parameter is allowed")
|
||||
|
||||
component_values = request.args.getlist("component")
|
||||
if len(component_values) > 1:
|
||||
return abort(400, "Only one component query parameter is allowed")
|
||||
|
||||
storage_file_id = file_id
|
||||
if component_values:
|
||||
storage_file_id = f"{file_id}?{urlencode({'component': component_values[0]})}"
|
||||
|
||||
stream, headers = await current_app.convex.open_storage_stream(storage_file_id, add_api_path=True)
|
||||
if 'Content-Type' not in headers:
|
||||
headers['Content-Type'] = 'application/octet-stream'
|
||||
|
||||
return Response(stream, headers=headers)
|
||||
|
||||
Reference in New Issue
Block a user