from flask import Flask, Response, request, send_from_directory from flask_cors import CORS from urllib.parse import urlparse import sys, requests app = Flask(__name__) VERSION = '1.1.0' FLASK_RUN_PORT = sys.argv[1] DATA_PATH = sys.argv[2] FLASK_ENV = sys.argv[3] FLASK_DEBUG = sys.argv[4] app = Flask(__name__, static_url_path='') app.url_map.strict_slashes = False CORS(app) ''' =================== URLs for Web Apps ====================== Works for any numbers of sub paths ''' @app.route('/<p1>', methods=['GET']) @app.route('/<p1>/<path:p2>', methods=['GET']) def x(p1, p2=''): path = p1 if p2: path = path + '/' + p2 app.logger.debug('[path] ' + path) return send_from_directory(DATA_PATH, path) ''' =================== Proxy for CouchDB access ============== The following works like a proxy server: A flask server URL of the form "http://127.0.0.1:8081/xxxx/vl_db/000_SERVERS" will be forwarded to the real CouchDB URL "http://127.0.0.1:xxxx/vl_db/000_SERVERS" The part 'xxxx' can be any integer as a future port address for couchdb. see: https://stackoverflow.com/questions/6656363/proxying-to-another-web-service-with-flask ''' @app.route('/<int:real_port>/', \ methods=['GET','PUT','POST','HEAD','DELETE','OPTIONS']) @app.route('/<int:real_port>/<path:p>', methods=['GET','PUT','POST','HEAD','DELETE','OPTIONS']) def couchdb_proxy(real_port, p=''): q = request.query_string.decode(); path = p if q: path = path + '?' + q host = urlparse(request.base_url).hostname scheme = urlparse(request.base_url).scheme new_url = '{}://{}:{}/{}'.format(scheme, host, real_port, path) app.logger.debug('[old couchdb url] ' + request.url) app.logger.debug('[new couchdb url] ' + new_url) resp = requests.request( method=request.method, url=new_url, headers={key: value for (key, value) in request.headers if key != 'Host'}, data=request.get_data(), cookies=request.cookies, allow_redirects=False) excluded_headers = ['content-encoding', 'content-length', \ 'transfer-encoding', 'connection'] headers = [(name, value) for (name, value) in resp.raw.headers.items() if name.lower() not in excluded_headers] response = Response(resp.content, resp.status_code, headers) return response @app.route('/') @app.route('/index.html') def home(): return '''<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Webapps Deliverer</title> </head> <body> <h3>VacLab: Combined web and CouchDB proxy service</h3>Version: {} </body> </html>'''.format(VERSION) @app.route('/version') def version(): return VERSION + '\n' if __name__ == '__main__': app.config['ENV'] = FLASK_ENV app.config['DEBUG'] = FLASK_DEBUG app.run(host='0.0.0.0', port=FLASK_RUN_PORT)