From f47be23658534e4b28d2e7cec3b368a5881c87b3 Mon Sep 17 00:00:00 2001 From: Andre Miller Date: Tue, 20 Jan 2015 15:33:33 +0200 Subject: [PATCH] CORS support now uses flask-cor extension --- beetsplug/web/__init__.py | 25 +++++------ beetsplug/web/crossdomaindec.py | 73 --------------------------------- setup.py | 2 +- 3 files changed, 12 insertions(+), 88 deletions(-) delete mode 100644 beetsplug/web/crossdomaindec.py diff --git a/beetsplug/web/__init__.py b/beetsplug/web/__init__.py index b3114dbab..9ab7619e0 100644 --- a/beetsplug/web/__init__.py +++ b/beetsplug/web/__init__.py @@ -22,7 +22,6 @@ from flask import g from werkzeug.routing import BaseConverter, PathConverter import os import json -from crossdomaindec import crossdomain, set_cors_origin # Utilities. @@ -165,7 +164,6 @@ def before_request(): # Items. @app.route('/item/') -@crossdomain() @resource('items') def get_item(id): return g.lib.get_item(id) @@ -173,14 +171,12 @@ def get_item(id): @app.route('/item/') @app.route('/item/query/') -@crossdomain() @resource_list('items') def all_items(): return g.lib.items() @app.route('/item//file') -@crossdomain() def item_file(item_id): item = g.lib.get_item(item_id) response = flask.send_file(item.path, as_attachment=True, @@ -190,7 +186,6 @@ def item_file(item_id): @app.route('/item/query/') -@crossdomain() @resource_query('items') def item_query(queries): return g.lib.items(queries) @@ -199,7 +194,6 @@ def item_query(queries): # Albums. @app.route('/album/') -@crossdomain() @resource('albums') def get_album(id): return g.lib.get_album(id) @@ -207,21 +201,18 @@ def get_album(id): @app.route('/album/') @app.route('/album/query/') -@crossdomain() @resource_list('albums') def all_albums(): return g.lib.albums() @app.route('/album/query/') -@crossdomain() @resource_query('albums') def album_query(queries): return g.lib.albums(queries) @app.route('/album//art') -@crossdomain() def album_art(album_id): album = g.lib.get_album(album_id) return flask.send_file(album.artpath) @@ -230,7 +221,6 @@ def album_art(album_id): # Artists. @app.route('/artist/') -@crossdomain() def all_artists(): with g.lib.transaction() as tx: rows = tx.query("SELECT DISTINCT albumartist FROM albums") @@ -241,7 +231,6 @@ def all_artists(): # Library information. @app.route('/stats') -@crossdomain() def stats(): with g.lib.transaction() as tx: item_rows = tx.query("SELECT COUNT(*) FROM items") @@ -267,7 +256,8 @@ class WebPlugin(BeetsPlugin): self.config.add({ 'host': u'127.0.0.1', 'port': 8337, - 'cors_origin': 'http://127.0.0.1', + 'cors': False, + 'cors_origin': '*', }) def commands(self): @@ -282,9 +272,16 @@ class WebPlugin(BeetsPlugin): if args: self.config['port'] = int(args.pop(0)) - set_cors_origin(self.config['cors_origin']) - app.config['lib'] = lib + + ## Enable CORS if required + if self.config['cors']: + from flask.ext.cors import CORS + app.config['CORS_ALLOW_HEADERS'] = "Content-Type" + app.config['CORS_RESOURCES'] = { + r"/*": {"origins": self.config['cors_origin'].get(str)} + } + cors = CORS(app) app.run(host=self.config['host'].get(unicode), port=self.config['port'].get(int), debug=opts.debug, threaded=True) diff --git a/beetsplug/web/crossdomaindec.py b/beetsplug/web/crossdomaindec.py deleted file mode 100644 index 8411c6fe8..000000000 --- a/beetsplug/web/crossdomaindec.py +++ /dev/null @@ -1,73 +0,0 @@ -# Decorator for the HTTP Access Control -# By Armin Ronacher -# http://flask.pocoo.org/snippets/56/ -# -# Cross-site HTTP requests are HTTP requests for resources from a different -# domain than the domain of the resource making the request. -# For instance, a resource loaded from Domain A makes a request for a resource -# on Domain B. The way this is implemented in modern browsers is by using -# HTTP Access Control headers -# -# https://developer.mozilla.org/en/HTTP_access_control -# -# The following view decorator implements this -# -# Note that some changes have been made to the original snippet -# to allow changing the CORS origin after the decorator has been attached -# This was done because the flask routing functions are defined before the -# beetsplug hook is called. - -from datetime import timedelta -from flask import make_response, request, current_app -from functools import update_wrapper - -cors_origin = 'http://127.0.0.1' - - -def set_cors_origin(origin): - global cors_origin - cors_origin = origin - - -def get_cors_origin(): - return cors_origin - - -def crossdomain(methods=None, headers=None, - max_age=21600, attach_to_all=True, - automatic_options=True): - if methods is not None: - methods = ', '.join(sorted(x.upper() for x in methods)) - if headers is not None and not isinstance(headers, basestring): - headers = ', '.join(x.upper() for x in headers) - if isinstance(max_age, timedelta): - max_age = max_age.total_seconds() - - def get_methods(): - if methods is not None: - return methods - - options_resp = current_app.make_default_options_response() - return options_resp.headers['allow'] - - def decorator(f): - def wrapped_function(*args, **kwargs): - if automatic_options and request.method == 'OPTIONS': - resp = current_app.make_default_options_response() - else: - resp = make_response(f(*args, **kwargs)) - if not attach_to_all and request.method != 'OPTIONS': - return resp - - h = resp.headers - - h['Access-Control-Allow-Origin'] = get_cors_origin() - h['Access-Control-Allow-Methods'] = get_methods() - h['Access-Control-Max-Age'] = str(max_age) - if headers is not None: - h['Access-Control-Allow-Headers'] = headers - return resp - - f.provide_automatic_options = False - return update_wrapper(wrapped_function, f) - return decorator diff --git a/setup.py b/setup.py index 36998d39a..a4d35c6bf 100755 --- a/setup.py +++ b/setup.py @@ -102,7 +102,7 @@ setup( 'echonest': ['pyechonest'], 'lastgenre': ['pylast'], 'mpdstats': ['python-mpd'], - 'web': ['flask'], + 'web': ['flask', 'flask-cors'], 'import': ['rarfile'], }, # Non-Python/non-PyPI plugin dependencies: