import os import json import time import requests import urllib3 import base64 from flask import Flask, render_template, request, jsonify # Suppress InsecureRequestWarning for verify=False urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) app = Flask(__name__) app.secret_key = os.urandom(24) app.config['MAX_CONTENT_LENGTH'] = 32 * 1024 * 1024 # 32MB limit # Standard Jinja2 delimiters are used. # Vue.js will be configured to use ['${', '}'] to avoid conflict. @app.route('/') def index(): return render_template('index.html') @app.route('/api/proxy', methods=['POST']) def proxy_request(): try: data = request.json if not data: return jsonify({'error': 'No data provided'}), 400 method = data.get('method', 'GET').upper() url = data.get('url') headers = data.get('headers', {}) body = data.get('body', None) params = data.get('params', {}) if not url: return jsonify({'error': 'URL is required'}), 400 # Ensure headers is a dict if not isinstance(headers, dict): headers = {} start_time = time.time() # Prepare arguments kwargs = { 'method': method, 'url': url, 'headers': headers, 'params': params, 'timeout': 60, # Increased timeout 'verify': False, # Allow testing local/self-signed endpoints 'allow_redirects': True } # Handle Body if body: content_type = '' # Case insensitive search for Content-Type for k, v in headers.items(): if k.lower() == 'content-type': content_type = v.lower() break if 'application/json' in content_type: if isinstance(body, str): try: # Try to parse to ensure it's valid JSON if we want to send as json kwarg json_body = json.loads(body) kwargs['json'] = json_body except: # Send as raw string if it fails to parse kwargs['data'] = body else: kwargs['json'] = body else: # x-www-form-urlencoded or plain text kwargs['data'] = body.encode('utf-8') if isinstance(body, str) else body resp = requests.request(**kwargs) duration = (time.time() - start_time) * 1000 # ms # Format response headers resp_headers = dict(resp.headers) resp_content_type = resp_headers.get('Content-Type', '').lower() # Determine how to return data is_binary = False is_json = False resp_data = None # Check for binary content types (images, pdfs, audio, etc.) binary_types = ['image/', 'audio/', 'video/', 'application/pdf', 'application/octet-stream', 'application/zip'] if any(bt in resp_content_type for bt in binary_types): is_binary = True resp_data = base64.b64encode(resp.content).decode('utf-8') else: # Try to parse response body as JSON try: resp_data = resp.json() is_json = True except: # Fallback to text resp_data = resp.text return jsonify({ 'status': resp.status_code, 'status_text': resp.reason, 'headers': resp_headers, 'data': resp_data, 'is_json': is_json, 'is_binary': is_binary, 'content_type': resp_headers.get('Content-Type', ''), 'duration': round(duration, 2), 'size': len(resp.content) }) except requests.exceptions.RequestException as e: return jsonify({ 'error': str(e), 'duration': round((time.time() - (start_time if 'start_time' in locals() else time.time())) * 1000, 2) }), 500 except Exception as e: return jsonify({ 'error': f"Internal Server Error: {str(e)}", 'duration': 0 }), 500 if __name__ == '__main__': port = int(os.environ.get('PORT', 7860)) app.run(host='0.0.0.0', port=port, debug=True)