From 69e3a5a25d65e6ece2419404e27c9be47faad183 Mon Sep 17 00:00:00 2001 From: Kumi Date: Sat, 3 Aug 2024 16:32:44 +0200 Subject: [PATCH] feat: add streaming and error handling to proxy route Introduced streaming support in the proxy route to handle large data transfers more efficiently without loading everything into memory at once. Added error handling for HTTP errors and content-type detection failures to provide more robust and user-friendly responses. Updated import statements to reflect new dependencies. --- app.py | 48 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/app.py b/app.py index 90fd588..5000c96 100644 --- a/app.py +++ b/app.py @@ -1,22 +1,50 @@ -from flask import Flask, redirect, render_template, request +from flask import Flask, render_template, request, Response, abort +from werkzeug.exceptions import InternalServerError from urllib.request import urlopen +from urllib.error import HTTPError +from urllib.parse import unquote app = Flask(__name__) -@app.route('/') + +@app.route("/") def home(): domain = request.url_root - return render_template('index.html', domain=domain) + return render_template("index.html", domain=domain) -@app.route('/') + +@app.route("/") def proxy(url): - jsdelivr_url = f'https://cdn.jsdelivr.net/{url}' + jsdelivr_url = f"https://cdn.jsdelivr.net/{url}" - response = urlopen(jsdelivr_url) - content = response.read() + def generate(): + # Subfunction to allow streaming the data instead of + # downloading all of it at once + try: + with urlopen(unquote(url)) as data: + while True: + chunk = data.read(1024 * 1024) + if not chunk: + break + yield chunk + except HTTPError as e: + abort(e.code) - return content + try: + with urlopen(unquote(jsdelivr_url)) as data: + content_type = data.headers["content-type"] + except HTTPError as e: + abort(e.code) + except KeyError: + raise InternalServerError() -if __name__ == '__main__': - app.run() \ No newline at end of file + headers = dict() + filename = url.split("/")[-1] + headers["Content-Disposition"] = f'attachment; filename="{filename}"' + + return Response(generate(), content_type=content_type, headers=headers) + + +if __name__ == "__main__": + app.run()